bol-van/zapret
GitHub: bol-van/zapret
跨平台DPI绕过工具,通过本地数据包 manipulation 技术对抗网络审查,无需依赖第三方服务器。
Stars: 14518 | Forks: 1008
# 注意,谨防诈骗
zapret 是自由且开源的。
任何强迫您仅从其资源下载 zapret、要求删除链接、视频、文件,并以版权为由进行辩解的人,其本身即违反了[许可证](./LICENSE.txt)。
然而,这并不排除[自愿捐赠](#поддержать-разработчика)。
# zapret
此版本的 zapret 已不再开发,处于 EOL (End-Of-Life) 模式。不会再有新功能。仅提供错误修复。
[当前版本 - zapret 2](https://github.com/bol-van/zapret2)
# 多语言 README
[](./readme.en.md)
[](./readme.md)
- [为什么需要这个](#зачем-это-нужно)
- [快速入门](#быстрый-старт)
- [工作原理](#как-это-работает)
- [俄罗斯目前的现状](#что-сейчас-происходит-в-россии)
- [如何在 linux 系统中实际实现](#как-это-реализовать-на-практике-в-системе-linux)
- [什么时候不起作用](#когда-это-работать-не-будет)
- [nfqws](#nfqws)
- [DPI 去同步攻击](#атака-десинхронизации-dpi)
- [伪造包 (FAKES)](#фейки)
- [伪造包修改](#модификация-фейков)
- [TCP 分段](#tcp-сегментация)
- [序列号覆盖 (SEQUENCE NUMBERS)](#перекрытие-sequence-numbers)
- [IP_ID 分配](#назначение-ip_id)
- [IPV6 特定模式](#специфические-режимы-ipv6)
- [原始数据修改](#модификация-оригинала)
- [重复包 (DUPLICATES)](#дубликаты)
- [组合去同步方法](#комбинирование-методов-десинхронизации)
- [IP 缓存](#кэш-ip)
- [DPI 对服务器响应的反应](#реакция-dpi-на-ответ-сервера)
- [SYNACK 模式](#режим-synack)
- [SYNDATA 模式](#режим-syndata)
- [虚拟机](#виртуальные-машины)
- [CONNTRACK](#conntrack)
- [重组 (REASSEMBLING)](#реассемблинг)
- [UDP 支持](#поддержка-udp)
- [IP 分片](#ip-фрагментация)
- [多重策略](#множественные-стратегии)
- [WIFI 过滤](#фильтрация-по-wifi)
- [NFQWS 的 IPTABLES 设置](#iptables-для-nfqws)
- [NFQWS 的 NFTABLES 设置](#nftables-для-nfqws)
- [FLOW OFFLOADING](#flow-offloading)
- [硬件特性](#особенности-железок)
- [服务器端的异常行为](#дурение-со-стороны-сервера)
- [tpws](#tpws)
- [TPWS 中的 TCP 分段](#tcp-сегментация-в-tpws)
- [TLSREC](#tlsrec)
- [MSS](#mss)
- [其他干扰参数](#другие-параметры-дурения)
- [多重策略](#множественные-стратегии-1)
- [服务参数](#служебные-параметры)
- [TPWS 的 IPTABLES 设置](#iptables-для-tpws)
- [TPWS 的 NFTABLES 设置](#nftables-для-tpws)
- [ip2net](#ip2net)
- [mdig](#mdig)
- [获取被封锁 IP 列表的方法](#способы-получения-списка-заблокированных-ip)
- [按域名过滤](#фильтрация-по-именам-доменов)
- [autohostlist 过滤模式](#режим-фильтрации-autohostlist)
- [检查运营商](#проверка-провайдера)
- [参数选择](#выбор-параметров)
- [结合防火墙管理系统或自定义启动系统](#прикручивание-к-системе-управления-фаерволом-или-своей-системе-запуска)
- [自定义 (custom) 方案](#вариант-custom)
- [简单安装](#простая-установка)
- [在 systemd 下安装](#установка-под-systemd)
- [在 openwrt 上简单安装](#простая-установка-на-openwrt)
- [在磁盘空间极度紧缺的 openwrt 上安装](#установка-на-openwrt-в-режиме-острой-нехватки-места-на-диске)
- [Android](#android)
- [华为移动调制解调器和路由器](#мобильные-модемы-и-роутеры-huawei)
- [FreeBSD, OpenBSD, MacOS](#freebsd-openbsd-macos)
- [Windows](#windows)
- [其他固件](#другие-прошивки)
- [通过第三方主机绕过封锁](#обход-блокировки-через-сторонний-хост)
- [为什么值得购买 VPS](#почему-стоит-вложиться-в-покупку-vps)
- [支持开发者](#поддержать-разработчика)
## 为什么需要这个
对抗 DPI 的独立工具,无需连接任何第三方服务器。可以帮助绕过 HTTP(S) 网站的封锁或限速,以及针对 TCP 和 UDP 协议的签名分析,例如用于封锁 VPN。
该项目主要针对运行 OpenWrt 的低功耗嵌入式设备 - 路由器。支持传统的 Linux 系统、FreeBSD、OpenBSD,部分支持 macOS。在某些情况下,可以将该解决方案自行适配到各种固件中。
大部分功能可在 Windows 上运行。
## 快速入门
- [Linux/openWrt](./quick_start.md)
- [Windows](./quick_start_windows.md)
## 工作原理
在最简单的情况下,您面对的是被动 DPI。被动 DPI 可以从流中读取流量,可以注入自己的数据包,但不能阻止通过的数据包。如果请求是“坏的”,被动 DPI 会注入 RST 数据包,可选地辅以 HTTP 重定向数据包。如果伪造包仅注入给客户端,这种情况下可以通过 iptables 命令根据特定条件丢弃 RST 和/或重定向到存根页面,这些条件需要针对每个运营商单独挑选。这样我们就绕过了禁止触发后的后果。如果被动 DPI 也向服务器发送 RST 数据包,那么您对此无能为力。您的任务是防止禁止触发器的激活。仅靠 iptables 已经不够了。该项目正是旨在防止禁止的触发,而不是消除其后果。
主动 DPI 串联在线路中,可以根据任何标准丢弃数据包,包括识别 TCP 流并阻止属于该流的任何数据包。
如何防止禁止触发器的激活?发送 DPI 意料之外的内容,从而破坏其识别请求和阻止请求的算法。
某些 DPI 无法识别分成 TCP 段的 HTTP 请求。例如,请求
形式 `GET / HTTP/1.1\r\nHost: kinozal.tv......`
我们分两部分发送:首先是 `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://web.archive.org/web/20230331233644/https://habr.com/ru/post/335436/ \
https://geneva.cs.umd.edu/papers/geneva_ccs19.pdf
## 俄罗斯目前的现状
以前,在广泛部署 TSPU 系统之前,运营商使用了各种各样的 DPI。有些是主动的,有些是被动的。现在简单 iptables 的时代已经彻底结束。到处都是主动的 TSPU DPI,但在某些地方,旧的大杂烩 DPI 可能仍保持开启状态。在这种情况下,必须同时绕过多个 DPI。越来越多的非清单封锁,您只能通过某些内容不可用的事实来了解,列表中没有这些内容。某些 IP 地址范围(无法自动绕过)和协议(VPN)被封锁。在某些 IP 范围上,使用了更严格的过滤器,可以识别通过分段进行欺骗的尝试。这应该与某些试图以此方式欺骗 DPI 的服务有关。
## 如何在 linux 系统中实际实现
简而言之,方案可以按以下模式分类:
1. 被动 DPI,不向服务器发送 RST。针对运营商单独调整的 iptables 命令会有所帮助。在 rutracker 的“绕过封锁 - 其他方式”部分有一个单独的主题讨论这个问题。本项目不考虑这一点。如果您不让禁止触发器激活,就不必处理其后果。
2. 流级别的 TCP 连接修改。通过 proxy 或 transparent proxy 实现。
3. 数据包级别的 TCP 连接修改。通过 NFQUEUE 队列处理程序和 raw 套接字实现。
对于方案 2 和 3,分别实现了程序 tpws 和 nfqws。为了让它们工作,需要使用正确的参数启动它们,并通过 iptables 或 nftables 将特定流量重定向到它们。
## 什么时候不起作用
* 如果 DNS 被篡改。这个问题很容易解决。
* 如果封锁是基于 IP 的。
* 如果连接通过能够重建 TCP 连接并遵循所有标准的过滤器。例如,我们被重定向到 squid。连接通过操作系统的完整 tcpip 协议栈。
该项目旨在欺骗 DPI,由于资源受限和流量巨大,DPI 被迫仅对其进行有限的解释。
欺骗完整的操作系统协议栈和完整的服务器应用程序是不可能的。
## nfqws
该程序是数据包修改器和 NFQUEUE 队列处理程序。对于 BSD 系统,有一个改编版本 - dvtws,从相同的源代码编译(见 [BSD 文档](./bsd.md))。
```
@|$ ; читать конфигурацию из файла. опция должна быть первой. остальные опции игнорируются.
--debug=0|1 ; 1=выводить отладочные сообщения
--dry-run ; проверить опции командной строки и выйти. код 0 - успешная проверка.
--version ; вывести версию и выйти
--comment ; любой текст (игнорируется)
--daemon ; демонизировать прогу
--pidfile= ; сохранить PID в файл
--user= ; менять uid процесса
--uid=uid[:gid] ; менять uid процесса
--qnum=N ; номер очереди N
--bind-fix4 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv4 пакетов
--bind-fix6 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv6 пакетов
--ctrack-timeouts=S:E:F[:U] ; таймауты внутреннего conntrack в состояниях SYN, ESTABLISHED, FIN, таймаут udp. по умолчанию 60:300:60:60
--ctrack-disable=[0|1] ; 1 или отсутствие аргумента отключает conntrack
--ipcache-lifetime= ; время жизни записей кэша IP в секундах. 0 - без ограничений.
--ipcache-hostname=[0|1] ; 1 или отсутствие аргумента включают кэширование имен хостов для применения в стратегиях нулевой фазы
--wsize=[:] ; менять tcp window size на указанный размер в SYN,ACK. если не задан scale_factor, то он не меняется (устарело !)
--wssize=[:] ; менять tcp window size на указанный размер в исходящих пакетах. scale_factor по умолчанию 0. (см. conntrack !)
--wssize-cutoff=[n|d|s]N ; изменять server window size в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--wssize-forced-cutoff=0|1 ; 1(default)=автоматически отключать wssize в случае обнаружения известного протокола
--synack-split=[syn|synack|acksyn] ; выполнить tcp split handshake. вместо SYN,ACK отсылать только SYN, SYN+ACK или ACK+SYN
--orig-ttl= ; модифицировать TTL оригинального пакета
--orig-ttl6= ; модифицировать ipv6 hop limit оригинальных пакетов. если не указано, используется значение --orig-ttl
--orig-autottl=[[:[-]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +5:3-64. "0:0-0" или "-" отключает функцию
--orig-autottl6=[[:[-]]|-] ; переопределение предыдущего параметра для ipv6
--orig-tcp-flags-set= ; устанавливать указанные tcp флаги (flags |= value). число , либо список через запятую : FIN,SYN,RST,PSH,ACK,URG,ECE,CWR,AE,R1,R2,R3
--orig-tcp-flags-unset= ; удалять указанные tcp флаги (flags &= ~value)
--orig-mod-start=[n|d|s]N ; применять orig-mod только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
--orig-mod-cutoff=[n|d|s]N ; применять orig-mod только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--dup= ; высылать N дубликатов до оригинала
--dup-replace=[0|1] ; 1 или отсутствие аргумента блокирует отправку оригинала. отправляются только дубликаты.
--dup-ttl= ; модифицировать TTL дубликатов
--dup-ttl6= ; модифицировать ipv6 hop limit дубликатов. если не указано, используется значение --dup-ttl
--dup-autottl=[[:[-]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +1:3-64. "0:0-0" или "-" отключает функцию
--dup-autottl6=[[:[-]]|-] ; переопределение предыдущего параметра для ipv6
--dup-tcp-flags-set= ; устанавливать указанные tcp флаги (flags |= value). число , либо список через запятую : FIN,SYN,RST,PSH,ACK,URG,ECE,CWR,AE,R1,R2,R3
--dup-tcp-flags-unset= ; удалять указанные tcp флаги (flags &= ~value)
--dup-fooling= ; дополнительные методики как сделать, чтобы дубликат не дошел до сервера. none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2
--dup-ts-increment= ; инкремент TSval для ts. по умолчанию -600000
--dup-badseq-increment= ; инкремент sequence number для badseq. по умолчанию -10000
--dup-badack-increment= ; инкремент ack sequence number для badseq. по умолчанию -66000
--dup-ip-id=same|zero|seq|rnd ; режим назначения ip_id для пакетов dup
--dup-start=[n|d|s]N ; применять dup только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
--dup-cutoff=[n|d|s]N ; применять dup только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--hostcase ; менять регистр заголовка "Host:" по умолчанию на "host:".
--hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета
--methodeol ; добавить перевод строки в unix стиле ('\n') перед методом и убрать пробел из Host: : "GET / ... Host: domain.com" => "\nGET / ... Host:domain.com"
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--domcase ; домен после Host: сделать таким : TeSt.cOm
--ip-id=seq|seqgroup|rnd|zero ; режим назначения ip_id для генерированных пакетов
--dpi-desync=[,][, ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
--dpi-desync-ttl= ; установить ttl для десинхронизирующих пакетов
--dpi-desync-ttl6= ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение --dpi-desync-ttl
--dpi-desync-autottl=[[:[-]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: 1:3-20. "0:0-0" или "-" отключает функцию
--dpi-desync-autottl6=[[:[-]]|-] ; переопределение предыдущего параметра для ipv6
--dpi-desync-tcp-flags-set= ; устанавливать указанные tcp флаги (flags |= value). число , либо список через запятую : FIN,SYN,RST,PSH,ACK,URG,ECE,CWR,AE,R1,R2,R3
--dpi-desync-tcp-flags-unset= ; удалять указанные tcp флаги (flags &= ~value)
--dpi-desync-fooling= ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2
--dpi-desync-repeats= ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты)
--dpi-desync-skip-nosni=0|1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI
--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=[+ofs]@|0xHEX ; чем заполнять фейковую часть overlap
--dpi-desync-fakedsplit-pattern=[+ofs]@|0xHEX ; чем заполнять фейки в fakedsplit/fakeddisorder
--dpi-desync-fakedsplit-mod=mod[,mod] ; может быть none, altorder=0|1|2|3 + 0|8|16
--dpi-desync-hostfakesplit-midhost=marker+N|marker-N ; маркер дополнительного разреза сегмента с оригинальным хостом. должен попадать в пределы хоста.
--dpi-desync-hostfakesplit-mod=mod[,mod] ; может быть none, host=, altorder=0|1
--dpi-desync-ipfrag-pos-tcp=<8..9216> ; позиция ip фрагментации tcp, начиная с транспортного заголовка. должно быть кратно 8, по умолчанию - 32.
--dpi-desync-ipfrag-pos-udp=<8..9216> ; позиция ip фрагментации udp, начиная с транспортного заголовка. должно быть кратно 8, по умолчанию - 8.
--dpi-desync-ts-increment= ; инкремент TSval для ts. по умолчанию -600000
--dpi-desync-badseq-increment= ; инкремент sequence number для badseq. по умолчанию -10000
--dpi-desync-badack-increment= ; инкремент ack sequence number для badseq. по умолчанию -66000
--dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных
--dpi-desync-fake-tcp-mod=mod[,mod] ; список через запятую режимов runtime модификации tcp фейков (любых) : none, seq
--dpi-desync-fake-http=[+ofs]@|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному www.iana.org
--dpi-desync-fake-tls=[+ofs]@|0xHEX|![+offset] ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному. '!' = стандартный фейк
--dpi-desync-fake-tls-mod=mod[,mod] ; список через запятую режимов runtime модификации фейков : none,rnd,rndsni,sni=,dupsid,padencap
--dpi-desync-fake-unknown=[+ofs]@|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
--dpi-desync-fake-syndata=[+ofs]@|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
--dpi-desync-fake-quic=[+ofs]@|0xHEX ; файл, содержащий фейковый QUIC Initial
--dpi-desync-fake-wireguard=[+ofs]@|0xHEX ; файл, содержащий фейковый wireguard handshake initiation
--dpi-desync-fake-dht=[+ofs]@|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-discord=[+ofs]@|0xHEX ; файл, содержащий фейковый пейлоад Discord протокола нахождения IP адреса для голосовых чатов для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-stun=[+ofs]@|0xHEX ; файл, содержащий фейковый пейлоад STUN протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-unknown-udp=[+ofs]@|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-udplen-increment= ; на сколько увеличивать длину udp пейлоада в режиме udplen
--dpi-desync-udplen-pattern=[+ofs]@|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули
--dpi-desync-start=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
--dpi-desync-cutoff=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--hostlist= ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются, если хост не начинается с '^'.
; в файле должен быть хост на каждой строке.
; список читается при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
; при изменении времени модификации файла он перечитывается автоматически по необходимости
; список может быть запакован в gzip. формат автоматически распознается и разжимается
; списков может быть множество. пустой общий лист = его отсутствие
; хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello.
--hostlist-domains= ; фиксированный список доменов через зяпятую. можно использовать # в начале для комментирования отдельных доменов.
--hostlist-exclude= ; не применять дурение к доменам из листа. может быть множество листов. схема аналогична include листам.
--hostlist-exclude-domains= ; фиксированный список доменов через зяпятую. можно использовать # в начале для комментирования отдельных доменов.
--hostlist-auto= ; обнаруживать автоматически блокировки и заполнять автоматический hostlist (требует перенаправления входящего трафика)
--hostlist-auto-fail-threshold= ; сколько раз нужно обнаружить ситуацию, похожую на блокировку, чтобы добавить хост в лист (по умолчанию: 3)
--hostlist-auto-fail-time= ; все эти ситуации должны быть в пределах указанного количества секунд (по умолчанию: 60)
--hostlist-auto-retrans-threshold= ; сколько ретрансмиссий запроса считать блокировкой (по умолчанию: 3)
--hostlist-auto-debug= ; лог положительных решений по autohostlist. позволяет разобраться почему там появляются хосты.
--new ; начало новой стратегии (новый профиль)
--skip ; не использовать этот профиль . полезно для временной деактивации профиля без удаления параметров.
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую.
--filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую.
--filter-l7= ; фильтр протокола L6-L7. поддерживается несколько значений через запятую. proto : http tls quic wireguard dht discord stun unknown
--filter-ssid=ssid1[,ssid2,ssid3,...] ; фильтр по имени wifi сети (только для linux)
--ipset= ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-ip= ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
--ipset-exclude= ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-exclude-ip= ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
```
`--debug` 允许将详细操作日志输出到控制台、syslog 或文件。选项的顺序可能很重要。`--debug` 最好放在最开始。选项是按顺序分析的。如果在检查选项时出现错误,而尚未分析到 `--debug`,则消息将不会输出到文件或 syslog。记录到文件时,进程不会保持文件打开。每次记录时都会打开文件,然后关闭。因此您可以随时删除文件,下次记录日志时会重新创建。但请注意,如果您以 root 身份启动进程,则 UID 将更改为非 root。开始时,日志文件的所有者会更改,否则将无法写入。如果您随后删除了文件,而进程在其目录中没有创建文件的权限,日志将不再继续。与其删除,最好使用 truncate。在 shell 中可以通过命令 `: >filename` 完成。
许多从文件加载二进制数据的参数支持从 hex 字符串或文件加载。
hex 字符串以 `0x` 开头。文件名可以按原样书写或使用前缀 `@`。
如果在 `@` 前缀前指定了 `+<数字>`,则表示文件内有效数据的偏移量。
文件可以从零位置完整加载,可以应用需要完整文件(TLS)的修改,
但传输将从偏移量位置开始。offset 必须小于文件长度。如果对数据块应用的修改减少了数据大小,并且 offset 不小于新的数据长度,则会出错。
### DPI 去同步攻击
其本质如下。获取原始请求,进行修改,添加伪造信息,
使得服务器操作系统将原始请求以未修改的形式传输给服务器进程,而 DPI 看到的是其他内容。
也就是它不会阻止的内容。服务器看到一样东西,DPI 看到另一样。DPI 不明白正在传输被禁止的请求,因此不会阻止它。
有一系列手段可以达到这个结果。
这可以是发送伪造包,使其到达 DPI 但不到达服务器。可以使用 TCP 级别的分段(分段)或 IP 级别的分片。
也有基于操纵 TCP sequence numbers 或混淆 TCP 段顺序的攻击。
方法可以以不同的方式组合。
### 伪造包
伪造包 是 nfqws 生成的独立数据包,携带针对 DPI 的虚假信息。
它们要么不应到达服务器,要么可以到达但必须被服务器丢弃。
否则会导致 TCP 连接断裂或传输流完整性受损,这必然导致资源损坏。
有一系列方法可以解决此任务。
* `md5sig` 添加 TCP 选项 **MD5 signature**。并非在所有服务器上都有效。通常只有 linux 丢弃带有 md5 的数据包。
需要显著增加 TCP 数据包的长度以容纳 TCP 选项。在处理多段请求(TLS Kyber)时,第一个数据包是填满 MTU 的。在较小的位置使用 fakedsplit/fakeddisorder 时,单独的 TCP 段足够大,以至于植入 md5 TCP 选项会导致 MTU 溢出和发送错误 "message too long"。`nfqws` 无法在 TCP 段之间重新分配数据,因此必须放弃 kyber,或者增加拆分位置,或者放弃 fakedsplit/fakeddisorder。
* `badsum` 破坏 TCP 校验和。如果您的设备位于不通过无效校验和包的 NAT 后,则无效。Linux 上最常见的 NAT 路由器配置不通过它们。大多数家用路由器基于 Linux。
不通的原因如下:默认的内核 sysctl 设置
`net.netfilter.nf_conntrack_checksum=1` 强制 conntrack 检查传入数据包的 TCP 和 UDP 校验和,并为无效校验和的数据包设置 state INVALID。通常在 iptables 规则中,会在 FORWARD 链中插入一条规则以丢弃状态为 INVALID 的数据包。这些因素共同导致 badsum 无法通过此类路由器。在 OpenWrt 中开箱即用 `net.netfilter.nf_conntrack_checksum=0`,在其他路由器中通常没有,而且并不总是可以更改。为了让 nfqws 能够通过路由器工作,需要在其上将指定的 sysctl 值设置为 0。nfqws 在路由器本身上无需此设置即可工作,因为本地创建的数据包从不检查校验和。如果路由位于另一个 NAT(例如运营商 NAT)之后,并且它不通 invalid packets,您将对此无能为力。但通常运营商还是会通过 badsum。在某些适配器/交换机/驱动程序上强制启用了 rx-checksum offload,badsum 数据包在进入操作系统之前就被截获。在这种情况下,如果能做什么的话,只能修改驱动程序,这是一项极其复杂的任务。已确定一些基于 mediatek 的路由器有这种行为。badsum 数据包离开客户端操作系统,但路由器无法通过 tcpdump 在 br-lan 上看到。同时,如果 nfqws 在路由器本身上执行,绕过可能会起作用。badsum 正常离开外部接口。
* `badseq` 将 TCP sequence number 增加特定值,从而将其移出 TCP window。
这些数据包肯定会被接收节点丢弃,但如果 DPI 依赖于 sequence numbers,也会被 DPI 丢弃。默认情况下 seq 偏移选择为 -10000。实践表明,某些 DPI 不允许 seq 超出特定窗口。然而,这种小的偏移可能在大量流传输和丢包时引起问题。如果您使用 `--dpi-desync-any-protocol`,可能需要设置 badseq increment 0x80000000。这将提供可靠的保证,即伪造包不会插入服务器的 TCP window。还注意到 badseq 会破坏某些 DPI 在分析 HTTP 时的逻辑,导致连接挂起。而且在相同的 DPI 上,带 badseq 的 TLS 工作正常。
* `TTL` 似乎是最好的选择,但它需要针对每个运营商进行单独调整。如果 DPI 位于运营商本地站点之外,您可能会切断对自己网站的访问。由于主干网上存在 TSPU,情况更加复杂,这迫使 TTL 设置得相当高,增加了伪造包穿透到服务器的风险。需要手动填充 IP 排除列表。可以将 md5sig 与 TTL 一起使用。这不会破坏任何东西,但为“坏”数据包通过 TTL 到达的站点提供了良好的工作机会。如果无法找到自动解决方案,请使用文件 `zapret-hosts-user-exclude.txt`。某些路由器 stock firmware 固定传出 TTL,不禁用此选项将无法通过它们工作。应如何选择 TTL:找到绕过仍然有效的最小值。这就是您 DPI 的跳数。
* `hopbyhop` 仅适用于 ipv6。添加 ipv6 extension header `hop-by-hop options`。在 `hopbyhop2` 变体中添加 2 个头,这违反了标准,并保证在所有操作系统中被协议栈丢弃。
一个 hop-by-hop 头被所有操作系统接受,但是在某些通道/运营商上,此类数据包可能会被过滤掉而无法到达。计算是基于 DPI 会分析带有 hop-by-hop 的数据包,但由于运营商的过滤器,它要么无法到达目的地,要么被服务器丢弃,因为有两个头。
* `datanoack` 发送移除了 TCP 标志 ACK 的伪造包。服务器不接受此类包,但 DPI 可能接受。此技术可能会破坏 NAT,并且并不总是适用于 iptables(如果使用 masquerade),即使是来自本地系统(在路由器上 ipv4 几乎总是如此)。在没有 masquerade 的 iptables 系统和 nftables 上无限制地工作。实验发现,许多运营商 NAT 不丢弃这些数据包,因此即使使用内部运营商 IP 也能工作。但它无法通过 Linux NAT,因此在家庭路由器后面,此技术很可能不起作用,但可能从路由器本身起作用。如果通过有线连接并且在路由器上启用了硬件加速,也可能通过路由器工作。
* 使用 `--dpi-desync-tcp-flags-set` 和 `--dpi-desync-tcp-flags-unset` 操纵 TCP 标志。可以制作服务器不接受但 DPI 接受的无效标志组合。例如,在伪造包中设置 SYN。但这可能并不适用于所有服务器。
`datanoack` 可以替换为 `--dpi-desync-tcp-flags-unset=ACK`。
具有无效标志的数据包在通过 NAT 时可能会被丢弃。
* `ts` 将 ts increment 的值(默认为 -600000)加到 TCP 时间戳的 TSval 值上。服务器在特定范围内丢弃具有 TSval 的数据包。根据实际测试,增量应该在 -100 到 -0x80000000 之间。
timestamps 由客户端操作系统生成。在 Linux 中,时间戳默认开启,在 Windows 中默认关闭。
可以通过命令 `netsh interface tcp set global timestamps=enabled` 开启。
ts fooling 需要开启时间戳,否则不起作用。必须在每个客户端设备上开启。
TSecr 保持不变。还需要服务器理解 timestamps,但这在大多数情况下是如此。
* `autottl`。该模式的本质是自动确定 TTL,使数据包几乎肯定通过 DPI 并且差一点不到达服务器(`--dpi-desync-autottl`)。或者相反 - TTL 勉强够用,使其仍然到达服务器(见 `--dup-autottl`, `--orig-autottl`)。
获取基本 TTL 值 64,128,255,查看传入数据包(是的,需要将第一个传入数据包定向到 nfqws!)。
计算路径长度,加上 `delta`。delta 可以是正的或负的。
要指定正增量,需要在数字前加上一元符号 **+**。
如果不存在或存在一元符号 **-**,则增量被认为是负的。
如果 TTL 超出 min,max 范围,则取 min,max 值以适应范围。如果此时增量为负且得到的 TTL 大于路径长度,或者增量为正且得到的 TTL 小于路径长度,
则自动机制失败,取固定值:`--dpi-desync-ttl`, `--orig-ttl`, `--dup-ttl`。
该技术可以解决整个网络到处都是障碍(DPI, TSPU)的问题,包括主干网。但潜在可能会出现故障。例如,当到特定服务器的传入和传出通道不对称时。某些服务器发出非标准 TTL(google),因此在它们那里结果完全是胡说八道。
如果不考虑这些例外,在某些运营商上,这种技术将运行良好,在其他运营商上会带来比好处更多的问题。在某些地方可能需要调整参数。最好与额外的限制器一起使用。
欺骗模式可以以任何方式组合。`--dpi-desync-fooling` 接受逗号分隔的多个值。
可以通过重复参数 `--dpi-desync-fake-???` 来指定多个伪造包,除了 `--dpi-desync-fake-syndata`。
伪造包将按指定顺序发送。`--dpi-desync-repeats` 重复每个发送的伪造包。
最终顺序将是:`fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake3 .....`
### 伪造包修改
默认情况下,任何 TCP 伪造包都以原始 sequence 发送,即使有多个。
如果设置 `--dpi-desync-fake-tcp-mod=seq`,则多个伪造包将以增加 sequence number 的方式发送,
就像它们是一个伪造包的 TCP 段一样。
nfqws 内置了基本的 TLS 伪造包。可以通过选项 `--dpi-desync-fake-tls` 重新定义。
重新定义伪造包允许使用任何数据作为 TLS 伪造包。
可以使用具有任何指纹和任何 SNI 的假 Client Hello。
可以使用 `--dpi-desync-fake-tls-mod` 在运行时进行某些修改。
其中一部分在处理每个 TLS Client Hello 时工作,并且可以适应发送的数据。
修改需要完整有效的 TLS Client Hello 作为伪造包,它们不适用于任意数据。
* `none`。不应用任何修改。
* `rnd`。随机化 `random` 和 `session id` 字段。对每个请求执行。
* `dupsid`。从传输的 TLS Client Hello 复制 `session ID`。优先级高于 `rnd`。对每个请求执行。
* `rndsni`。随机化 SNI。如果 SNI >=7 个字符,应用已知 TLD 的随机 2 级域名,否则用没有点的随机字符填充。在启动时执行一次。
* `sni=`。将 sni 替换为指定值。最大 SNI 长度 - 63 字节。TLS 伪造包的总长度和 TLS Client Hello 结构中的长度会改变。在启动时执行一次。如果与 `rndsni` 结合使用,在它之前执行。
* `padencap`。将 padding extension 扩展到传输的 TLS Client Hello 的大小(包括带 kyber 的多包变体)。如果缺少 padding,则将其添加到末尾。如果存在 - 要求 padding 是最后一个 extension。修正所有长度以营造传输的 TLS Client Hello 包含在 padding extension 中的假象。伪造包的大小不变。计算是基于 DPI 没有正确分析 sequence numbers。对每个请求执行。
默认情况下,如果未设置自定义 TLS 伪造包,则使用修改 `rnd,rndsni,dupsid`。如果设置了伪造包,则使用 `none`。
这对应于程序较旧版本的行为,并增加了 `dupsid` 功能。
如果设置了修改模式并且有多个 TLS 伪造包,则对每个应用最后的修改模式。
如果修改模式在伪造包之后设置,它将替换先前的模式。
因此可以对不同的伪造包使用不同的修改模式。
如果在启动阶段无法修改伪造包,程序将出错退出。
如果首先是 TLS 伪造包,为其设置了单次修改模式,然后是非 TLS 伪造包,则会出错。
需要使用 `--dpi-desync-fake-tls-mod=none'。
示例:`--dpi-desync-fake-tls=iana_org.bin --dpi-desync-fake-tls-mod=rndsni --dpi-desync-fake-tls=0xaabbccdd --dpi-desync-fake-tls-mod=none'
### TCP 分段
* `multisplit`。在 `--dpi-desync-split-pos` 指定的位置切割请求。
* `multidisorder`。在 `--dpi-desync-split-pos` 指定的位置切割请求并以相反的顺序发送。
* `fakedsplit`。以直接顺序混合伪造包和原始数据的各种变体
* `fakeddisorder`。以相反顺序混合伪造包和原始数据的各种变体
* `hostfakesplit` (altorder=0)。伪造请求中包含主机的部分:主机前的原始数据,主机伪造包,主机原始数据(+ 可选通过 midhost 标记切割),主机伪造包,主机后的原始数据
* `hostfakesplit` (altorder=1)。伪造请求中包含主机的部分:主机前的原始数据,主机伪造包,主机后的原始数据,主机原始数据(+可选通过 midhost 标记切割)
* `fakeddisorder`。类似于 `fakedsplit`,只是顺序相反:第 2 部分伪造包,第 2 部分,第 2 部分伪造包,第 1 部分伪造包,第 1 部分,第 1 部分伪造包。
对于 `fakedsplit` 和 `fakeddisorder`,提供了段顺序的变体。
参数 `--dpi-desync-fakedsplit-mod=altorder=N` 设置影响是否存在单独伪造包的数字:
具有拆分位置的多包请求部分的 `fakedsplit` altorder 模式:
* `altorder=0`。第 1 部分伪造包,第 1 部分,第 1 部分伪造包,第 2 部分伪造包,第 2 部分,第 2 部分伪造包
* `altorder=1`。第 1 部分,第 1 部分伪造包,第 2 部分伪造包,第 2 部分,第 2 部分伪造包
* `altorder=2`。第 1 部分,第 2 部分伪造包,第 2 部分,第 2 部分伪造包
* `altorder=3`。第 1 部分,第 2 部分伪造包,第 2 部分
具有拆分位置的多包请求部分的 `fakeddisorder` altorder 模式:
* `altorder=0`。第 2 部分伪造包,第 2 部分,第 2 部分伪造包,第 1 部分伪造包,第 1 部分,第 1 部分伪造包
* `altorder=1`。第 2 部分,第 2 部分伪造包,第 1 部分伪造包,第 1 部分,第 1 部分伪造包
* `altorder=2`。第 2 部分,第 1 部分伪造包,第 1 部分,第 1 部分伪造包
* `altorder=3`。第 2 部分,第 1 部分伪造包,第 1 部分
没有拆分位置的多包请求部分的 `fakedsplit` 和 `fakeddisorder` altorder 模式:
* `altorder=0`。伪造包,原始数据,伪造包
* `altorder=8`。原始数据,伪造包
* `altorder=16`。原始数据
最终数字 `altorder=N` 计算为这两组数字的总和。默认 `altorder=0`。
`fakedsplit`/`fakeddisorder` 中伪造包的内容由参数 `--dpi-desync-fakedsplit-pattern` 确定(默认为 0x00)。
伪造包的数据取自模式,偏移量对应于发送部分的偏移量,考虑到多包请求中的数据包偏移量。
伪造包的大小对应于发送部分的长度。
这些的目标是最大程度地复杂化在伪造包中识别原始数据的过程。
在 TLS kyber 上使用带 md5sig fooling 的 `fakedsplit` 或 `fakeddisorder` 可能会导致 "message too long" 错误,如果拆分位置很小,
因为 md5 TCP 选项会导致 MTU 超限。
'hostfakesplit' 模式的任务是以最小程度的伪造干预 - 正是在 DPI 用以决定阻止的请求部分。具体来说 - 主机名。
默认情况下,主机伪造包每次从 `[a-z0-9]` 集合中随机生成。如果长度超过 7 个字符,则在倒数第 3 个字符处放置一个点,模拟 TLD,最后 3 个字符填充几个已知 TLD 中的一个。
可以使用 `--dpi-desync-hostfakesplit-mod=host=` 重新定义生成模板。在后一种情况下,右侧始终是指定的 hostname。
左侧将填充随机字符作为子域,以达到原始主机的大小。示例:"www.networksolutions.com" -> "h8xmdba4tv7a8.google.com"。
如果原始主机的大小小于模板,模板将被切割:"habr.com" -> "ogle.com"。
如果原始主机的大小比模板大 1,将得到无效的空子域:"www.xxx.com" => ".google.com"。
因此,应使用允许的最短主机:"ya.ru", "vk.com"。
`--dpi-desync-hostfakesplit-mod=altorder=1` 允许将部分的顺序更改为替代方案。
`altorder=1` 发送片段的顺序使得在 DPI 上按顺序组装段时,他将获得完全组装的带有替换主机的原始请求。
真实主机在之后作为一个单独的段发送。也就是说,在这个变体中应用了 disorder 的变种。服务器接受具有违反顺序 sequence 的片段。
可以选择切割原始主机。例如,`--dpi-desync-hostfakesplit-midhost=midsld`。切割位置必须在主机内部。
仅当初始数据包切割不包括主机名位置时,才支持多包请求。在后一种情况下,欺骗被取消。
变体 `fakedsplit` 有几个替代的切割顺序 - 从 0 到 3。模式在参数 `--dpi-desync-fakedsplit-mod=altorder=N` 中设置。
每个后续 altorder 移除部分伪造包。
标记用于确定切割位置。
* **绝对正标记** - 数据包或数据包组内从开始的数字偏移。
* **绝对负标记** - 数据包或数据包组内从结束后一个字节开始的数字偏移。-1 表示最后一个字节。
* **相对标记** - 相对于数据包或数据包组内逻辑位置的正或负偏移。
相对位置:
* **method** - HTTP 方法的开始('GET', 'POST', 'HEAD', ...)。方法通常总是在位置 0,但由于 `--methodeol` 可能会移动。然后位置可能变为 1 或 2。
* **host** - 已知协议(http, TLS)中主机名的开始
* **endhost** - 主机名最后一个字节之后的字节
* **sld** - 主机名中 2 级域名的开始
* **endsld** - 主机名中 2 级域名最后一个字节之后的字节
* **midsld** - 主机名中 2 级域名的中间
* **sniext** - TLS 中 SNI extension 数据字段的开始。任何 extension 由 2 字节的 type 和 length 字段组成,后面是数据字段。
标记列表示例:`100,midsld,sniext+1,endhost-2,-10`。
在拆分数据包时,首先要解析标记 - 找到所有指定的相对位置并应用偏移量。
如果当前协议中不存在相对位置,则不应用并丢弃这些位置。
然后发生相对于数据包组中当前数据包偏移量的位置标准化(例如,带 kyber 的 TLS 多包请求)。
丢弃所有超出当前数据包范围的位置。剩余的按升序排序并删除重复项。
在 `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。
为了更明确,可以对不同的协议使用不同的配置文件,并仅指定一个肯定存在于该协议中的位置。
### 序列号覆盖
`seqovl` 在 TCP 段之一的开头添加 `seqovl` 字节,sequence number 减去 `seqovl` 的量。
对于 `split` - 在第一个段的开头,对于 `disorder` - 在倒数第二个发送段的开头(原始顺序中的第二个)。
在 `split` 的情况下,计算基于先前的发送(如果有的话)已经进入服务器应用程序的套接字,因此新到达的部分仅部分在
当前窗口范围内。前面的伪造部分被丢弃,剩余部分包含原始数据并
从窗口开始,因此进入套接字。服务器应用程序接收客户端实际发送的所有内容,
丢弃伪造的 out-of-window 部分。但 DPI 无法理解这一点,因此它会发生 sequence 去同步。
必须确保第一个段与 `seqovl` 一起不超过 MTU 长度。这种情况在 Linux 中自动识别,`seqovl` 被取消。
在其他系统中,这种情况无法识别,将导致连接断裂。因此选择第一个拆分位置和 `seqovl`,以便在任何情况下都不超过 MTU。
否则,欺骗可能不起作用或工作不稳定。
对于 `disorder`,重叠位于数据包倒数第二部分。
为简单起见,假设拆分为 2 部分,它们按 "2 1" 的顺序发送,原始顺序为 "1 2"。
必须确保 `seqovl` 小于第一个拆分位置,否则所有发送的内容将立即传输到套接字,包括伪造包,破坏应用层协议。
这种情况很容易被程序检测到,`seqovl` 被取消。增加数据包大小原则上是不可能的。
如果满足条件,第 2 部分数据包完全在窗口内,因此服务器操作系统完全接受它,包括伪造包。
但由于来自 1 数据包的初始部分数据尚未接收,伪造和真实数据保留在内核内存中,不发送到服务器应用程序。
一旦第 1 部分数据包到达,它就会重写内核内存中的伪造部分。
内核从 1 和 2 部分接收数据,然后发送到应用程序套接字。
所有 unix 操作系统的行为都是如此,除了 solaris - 保留最后接收的数据。
Windows 保留旧数据,因此在与 Windows 服务器工作时,带 seqovl 的 disorder 将导致连接挂起
。Solaris 几乎已死,windows 服务器很少。
如有必要可以使用列表。
该方法允许不使用 fooling 和 TTL。伪造包与真实数据混合。
`fakedsplit/fakeddisorder` 仍然添加额外的单独伪造包。
`seqovl` 在 `split` 变体中只能是绝对正值,因为它仅应用于第一个数据包。
在 `disorder` 变体中,允许使用所有标记变体。
它们会自动标准化为系列中的当前数据包。可以在 `midsld` 上拆分并在 `midsld-1` 上做 seqovl。
### IP_ID 分配
某些 DPI 会分析 ipv4 头的 ip_id 字段。保护措施是识别不同操作系统不典型的 ip_id 分配顺序,
但对于某些 anti-DPI 软件来说是典型的。通常,操作系统为每个后续数据包递增 ip_id。
例如,在 TSPU 上,伪造包和非伪造包重复非零 ip_id 会在 `googlevideo.com` IP 范围上触发阻止。
如果发送伪造包或额外的 TCP 段,顺序无论如何都会被打破,因为操作系统对插入的伪造包一无所知
并且不会将其 ip_id 计数器增加伪造包或额外 TCP 段的数量。
为了保持顺序,需要将整个连接拦截到底,这在资源上非常昂贵。
因此,在处理一系列生成的数据包后,ip_id 返回到操作系统知道的值。
参数 `ip-id` 属于配置文件,并设置在发送 nfqws 中生成的数据包时分配 ip_id 的模式。
* `seq`(默认):取真实数据包的最后一个 ip_id。后续生成的数据包获得递增 1 的 ip_id,除了 `multidisorder` 的情况。
对于 `multidisorder`,在有拆分位置的段内,ip_id 值增加部分的数量,然后每发送一个部分减少 1。
* `seqgroup`:与 `seq` 相同,但与原始段大小相同、伪装成原始段的伪造包获得相同的 ip_id。
* `rnd`:为所有生成的数据包分配随机 ip_id
* `zero`:为所有生成的数据包分配 ip_id=0。在这种情况下,Linux 和 BSD 将发送 0,Windows 将为所有数据包分配连续的 ip_id(从而自动解决了数据包计数器故障的问题)。
在 ipv6 头中没有 ip_id 字段,对于 ipv6 该参数被忽略。
### IPV6 特定模式
去同步模式 `hopbyhop`、`destopt` 和 `ipfrag1`(不要与 fooling 混淆!)仅适用于 ipv6,在于
将 `hop-by-hop options`、`destination options` 或 `fragment` 头添加到所有符合去同步条件的数据包中。
这里必须明白,添加头会增加数据包的大小,因此不能应用于
最大大小的数据包。这发生在传输大消息时。
如果无法发送数据包,欺骗将被取消,数据包将以原始形式发送。
计算是基于 DPI 会在主 `ipv6` 头的 next header 字段中看到 0,而不会在
extension 头中跳转寻找传输头。因此不会明白这是 TCP 或 UDP,并会在没有
分析的情况下通过数据包。也许某些 DPI 会中招。
可以与任何第 2 阶段模式结合,除了 `ipfrag1+ipfrag2` 变体。
例如,`hopbyhop,multisplit` 意味着将 TCP 数据包拆分为多个段,并在每个段中添加 hop-by-hop。
对于 `hopbyhop,ipfrag2`,头顺序将是:`ipv6,hop-by-hop`,`fragment`,`tcp/udp`。
如果没有特殊准备,`ipfrag1` 模式可能并不总是有效。见 `IP 分片` 部分。
### 原始数据修改
参数 `--orig-ttl` 和 `--orig-ttl6` 允许更改原始数据包的 TTL。
如果后续操作与原始数据有关,例如,TCP 分段,则源
数据是修改后的原始数据包。也就是说,在这个例子中,TCP 段将带有修改后的 TTL。
变体 `--orig-autottl` 和 `--orig-autottl6` 的工作方式类似于 `dpi-desync-autottl`,但针对原始数据包。
增量最好用一元符号 `+` 指定为正,否则原始数据将不到达服务器,您根本什么都得不到。
示例:`--orig-autottl=+5:3-64`。
`--orig-mod-start` 和 `--orig-mod-cutoff` 设置修改原始数据的开始和结束限制。
方案类似于 `--dpi-desync-start` 和 `--dpi-desync-cutoff`。
当 DPI 猎杀伪造包并在存在可疑迹象时阻止连接时,该功能可能很有用,
特别是伪造包相对于原始包的 TTL 更改。
### 重复包
重复包是原始数据包的副本,在它们之前发送。通过参数 `--dup=N` 启用,其中 N 是重复数量,
不包括原始包。`--dup-replace` 禁用原始包的发送。
只有在发送原始包而不重构的情况下,才会发送重复包。
例如,如果发生 TCP 分段,则原始包实际上被丢弃并替换为人工构造的段。
重复包不会被发送。这也适用于 ipv6 头组成的变化、DHT 的 tamper 模式等。
可以应用所有欺骗变体,就像 desync 一样:`--dup-ttl`、`--dup-ttl6`、`--dup-fooling`。这些数据包是否需要到达服务器以及以何种形式到达,您根据设想的策略决定。
变体 `--dup-autottl` 和 `--dup-autottl6` 的工作方式类似于 `dpi-desync-autottl`,但针对重复包。
增量可以用一元符号 `+` 指定为正,也可以为负。取决于您的想法。
示例:`--dup-autottl=-2:3-64`。
`--dup-start` 和 `--dup-cutoff` 设置应用重复策略的开始和结束限制。
方案类似于 `--dpi-desync-start` 和 `--dpi-desync-cutoff`。
当 DPI 检测到伪造包和原始包的特征差异时,该功能可以提供帮助。
可以尝试使用重复包迫使 DPI 接受整个会话是异常的。
例如,我们有一个从第一个 SYN 数据包开始就带有5 的 TCP 会话。这意味着后续的 MD5 将被视为正常。
### 组合去同步方法
在 dpi-desync 参数中,最多可以通过逗号指定 3 种模式。
* 0 阶段 - 假设在连接建立阶段工作:`synack`, `syndata`, `--wsize`, `--wssize`。[hostlist](#множественные-стратегии) 过滤器不作用于该阶段,除了[后面](#кэш-ip)描述的情况。
* 1 阶段 - 在原始数据包之前发送某些内容:`fake`, `rst`, `rstack`。
* 2 阶段 - 以修改后的形式发送原始数据包(例如,`fakedsplit` 或 `ipfrag2`)。
模式需要按阶段编号递增的顺序指定。
### IP 缓存
ipcache 是进程内存中的一种结构,允许通过 IP 地址和接口名称的键记住某些信息,
随后可以提取并用作缺失数据。目前,这用于以下情况:
1. IP,interface => hop count。缓存到服务器的跳数,以便从第一个数据包开始随后应用于 autottl,当时还没有响应。只要缓存中没有记录,autottl 就不会立即应用。在记录过期时间内的重复请求中,autottl 将立即应用。
2. IP => hostname。缓存主机名,不绑定到接口,以便随后应用于零阶段策略。该模式默认禁用,通过参数 `ipcache-hostname` 启用。
本技术属于实验性功能。其问题在于,域名与 IP 之间并没有严格的对应关系。多个域名可能指向同一个 IP 地址。
当发生冲突时,主机名会被替换为最后一次出现的值。
域名可能会在 CDN 上的不同 IP 之间切换。现在是一个地址,一小时后可能就是另一个。这个问题可以通过缓存记录的生命周期 `--ipcache-lifetime` 来解决。默认值为 2 小时。
然而,在某些情况下,使用这项技术可能利大于弊。请准备好应对乍看之下难以理解的行为,这只能通过 `--debug` 日志进行调查。
当发送 SIGUSR2 信号时,进程会将 ipcache 的内容输出到控制台。
### DPI 对服务器响应的反应
有些 DPI 会分析来自服务器的响应,特别是 ServerHello 中的证书,其中包含域名。
ClientHello 成功送达的标志是服务器发回的 ACK 包,其 ACK sequence 号对应于 ClientHello 的长度 +1。
在 disorder 模式下,通常会先收到部分确认(SACK),然后才是完整的 ACK。
如果 ACK 或 SACK 被替换为经过最小延迟后的 RST 包,那么说明 DPI 在请求阶段就已经切断了你的连接。
如果 RST 是在完整 ACK 经过大约相当于 ping 通服务器的延迟后才到达,那么 DPI 很可能是对服务器的响应做出了反应。
如果 ClientHello 令 DPI 满意,DPI 可能会停止跟踪流,而不再检查 ServerHello。
那你就是幸运的。Fake 模式可能生效。
如果它不停止并坚持检查 ServerHello,则可以尝试通过 `--wssize` 参数(参见 conntrack)强制服务器分批发送 ServerHello。
如果这也不起作用,那么在没有服务器端协助的情况下,恐怕很难有其他解决办法。
最佳解决方案是在服务器上启用 TLS 1.3 支持。在 TLS 1.3 中,服务器证书是加密传输的。
这是给所有被封锁网站管理员的建议。请启用 TLS 1.3。这样可以为绕过 DPI 提供更多可能性。
### SYNACK 模式
在 geneva 文档中,这被称为 "TCB turnaround"。这是一种试图误导 DPI 关于客户端和服务器角色的技术。
由于该模式会破坏 NAT 的工作,因此只有在攻击设备与 DPI 之间没有 NAT 时,该技术才可能生效。攻击无法通过 NAT 路由器进行,但可以从路由器本身发起。
要实现对通过流量的攻击,需要 nftables 和 [POSTNAT](#nftables-для-nfqws) 方案。
### SYNDATA 模式
这很简单。在 SYN 包中添加数据。如果不使用 TCP Fast Open (TFO),所有操作系统都会忽略这些数据,而 DPI 可能会处理它,而不管是否存在 TFO。
原始的 TFO 连接不会被触碰,因为这肯定会破坏它们。
如果没有指定具体参数,默认添加 16 个零字节。
### 虚拟机
在 VirtualBox 和 VMware 虚拟机的 NAT 模式下,nfqws 的许多数据包魔法技术无法工作。
TTL 会被强制替换,Fake 数据包无法通过。必须将网络配置为桥接模式 (bridge)。
### CONNTRACK
nfqws 包含有限的 TCP 连接状态跟踪 实现。
它是为了实现某些对抗 DPI 的方法而启用的。
conntrack 能够跟踪连接阶段:SYN、ESTABLISHED、FIN,以及双向的数据包数量和序列号。conntrack 可以“接收”双向或单向的数据包。
当检测到带有 SYN 或 SYN,ACK 标志的数据包时,连接会被加入跟踪表。
因此,如果需要 conntrack,iptables 重定向规则必须从第一个数据包开始将连接导向 nfqws,即使之后可以通过 connbytes 过滤器截断。
对于 UDP,第一个 UDP 数据包是进入跟踪表的触发器。它同时也决定了流的方向。
假定第一个 UDP 数据包是从客户端发送到服务器的。随后,所有具有匹配 `src_ip,src_port,dst_ip,dst_port` 的数据包都被视为属于该流,直到不活动超时。
conntrack 很简单,编写时并未考虑各种针对连接的攻击,它不验证序列号或校验和的有效性。它的任务只是服务于 nfqws 的需求,通常只接收传出流量,因此对外部网络的伪造不敏感。
一旦不再需要跟踪连接,或者由于不活动超时,连接就会从表中删除。
连接的每个阶段都有单独的超时设置。可以通过 `--ctrack-timeouts` 参数修改它们。
`--wssize` 允许从客户端更改发往服务器的 TCP 窗口大小,以便服务器将后续响应分部分发送。
为了对所有服务器操作系统生效,必须在发送触发分段的消息(例如 TLS ClientHello)之前的每个客户端传出数据包中更改窗口大小。这正是需要 conntrack 的原因,以便知道何时停止。如果不停地将 wssize 设为低值,速度将灾难性地下降。
在 Linux 中,这可以通过 connbytes 缓解,但在 BSD 系统中没有这种可能。
对于 HTTP(S),我们在发送第一个 HTTP 请求或 TLS ClientHello 后立即停止。
如果您处理的是非 HTTP(S) 协议,则需要使用参数 `--wssize-cutoff`。它设置 wssize 停止作用的界限。数字前的 `d` 前缀表示仅计算带有数据负载的数据包,`s` 前缀表示相对序列号,简而言之即客户端传输的字节数 +1。
如果出现带有 HTTP 请求或 TLS ClientHello 的数据包,wssize 操作将立即停止,无需等待 wssize-cutoff,除非指定了参数 `--wssize-forced-cutoff=0`。
如果您的协议倾向于长时间空闲,应通过 `--ctrack-timeouts` 增加 ESTABLISHED 阶段的超时时间。
默认超时很低,仅 5 分钟。
不要忘记,nfqws 依赖于接收到的数据包。如果您通过 connbytes 限制了数据包的输入,表中可能会留下处于 ESTABLISHED 阶段的挂起连接,它们只能通过超时断开。
要诊断 conntrack 状态,向 nfqws 进程发送 SIGUSR1 信号:`killall -SIGUSR1 nfqws`。
当前表格将输出到 nfqws 的 stdout。
通常,SYN 包中除了窗口大小外,客户端还发送 TCP 扩展 `scaling factor`。
**scaling factor** 代表窗口大小乘以 2 的幂:0=>1, 1=>2, 2=>4, ..., 8=>256, ...
在 wssize 参数中,scaling factor 通过冒号指定。
Scaling factor 只能降低,增加会被阻止,以防止服务器窗口大小超标。
为了强制服务器分段 ServerHello,避免 DPI 从服务器证书中提取服务器名称,最好使用 `--wssize=1:6`。主要规则是使 `scale_factor` 尽可能大,以便在恢复窗口大小后,最终窗口大小尽可能大。如果您设置为 64:0,速度将非常慢。
另一方面,不能让服务器的响应足够大,以至于 DPI 能在其中找到目标内容。
`--wssize` 不适用于包含主机列表的配置文件,因为它从连接一开始就起作用,此时还无法决定是否匹配列表。但是,包含 auto hostlist 的配置文件可以包含 --wssize。
`--wssize` 可能会降低速度和/或增加网站响应时间,因此如果有其他有效的绕过 DPI 方法,最好使用它们。
`--dpi-desync-cutoff` 允许设置一个界限,达到后停止应用 dpi-desync。
类似于 `--wssize-cutoff`,可以使用前缀 n, d, s。
与 `--dpi-desync-any-protocol=1` 结合使用时很有用。
对于倾向于空闲的连接,应修改 conntrack 超时。
如果连接从 conntrack 中消失并设置了 `--dpi-desync-cutoff` 选项,则不会应用 `dpi desync`。
### 重组
nfqws 支持对某些类型的请求进行重组。
目前支持 TLS 和 QUIC ClientHello。如果在 chrome 中启用后量子密码学 tls-kyber,这些请求可能会很长,通常占用 2 或 3 个数据包。从 chromium 124 开始,kyber 默认启用。
chrome 会随机化 TLS 指纹。SNI 可能出现在开头或结尾,也就是可能落入任何数据包中。有状态的 DPI 通常会在完全重组请求后才决定是否封锁。
当收到包含部分 ClientHello 的 TLS 或 QUIC 数据包时,开始重组过程,数据包被延迟直到重组完成才发送。重组完成后,数据包将根据完整的 ClientHello 进行去同步处理。
如果重组过程中出现任何错误,延迟的数据包将立即发送到网络,并取消去同步。
针对多段 TLS 有特殊的所有 tcp split 变体支持。
如果指定的分割位置大于第一个数据包的长度,则分割不一定是第一个数据包,而是落在最终位置上的那个数据包。
假设客户端发送了长度为 2000 的 TLS ClientHello,SNI 从 1700 开始,并设置了 `fake,multisplit` 选项,那么在第一个数据包之前是 fake,然后是原始的第一个数据包,而最后一个数据包被分成 2 个段。最终结果是开头有一个 fake 和 3 个真实段。
### UDP 支持
UDP 攻击的功能更加有限。UDP 只能在 IP 层面进行分片。
对于 UDP,只有 `fake`、`fakeknown`、`hopbyhop`、`destopt`、`ipfrag1`、`ipfrag2`、`udplen`、`tamper` 去同步模式有效。
第一阶段的模式包括 `fake`、`fakeknown`、`hopbyhop`、`destopt`、`ipfrag1`。第二阶段的模式包括 `ipfrag2`、`udplen`、`tamper`。
照例,可以组合第一阶段和第二阶段的模式,但不能组合同一阶段的两个模式。
`udplen` 将 UDP 数据包的大小增加 `--dpi-desync-udplen-increment` 指定的字节数。
填充默认为零,但可以指定自定义模式。
旨在欺骗基于数据包大小的 DPI。
如果用户协议没有严格绑定到 UDP 负载大小,这可能会奏效。
Tamper 模式意味着以特定于协议的方式修改已知协议的数据包。
目前仅适用于 DHT。
支持对 QUIC Initial 数据包的检测,包括解密内容和主机名,因此参数 `--hostlist` 有效。
可以识别 Wireguard 握手 initiation、DHT(以 'd1' 开头,以 'e' 结尾)、STUN 和 [Discord Voice IP Discovery](https://discord.com/developers/docs/topics/voice-connections#ip-discovery) 数据包。
要对其他协议进行去同步,必须指定 `--dpi-desync-any-protocol`。
已实现 UDP 的 conntrack。可以使用 --dpi-desync-cutoff。可以通过 `--ctrack-timeouts` 的第 4 个参数更改 UDP 的 conntrack 超时。
Fake 攻击仅对有状态的 DPI 有效,对基于单个数据包的分析无效。
默认 fake 填充为 64 个零。可以在 `--dpi-desync-fake-unknown-udp` 中指定文件。
### IP 分片
现代网络几乎不传输 IP 层面的分片 TCP。
对于 UDP,情况稍好,因为某些 UDP 协议可能依赖此机制(旧版 IKE)。
然而,有些地方也会拦截分片 UDP。
基于 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` 中查看解决此问题的示例。
有时需要使用参数 `raw_before_defrag=1` 加载 `ip6table_raw` 模块。
在 OpenWrt 中,模块参数在 `/etc/modules.d` 文件中的模块名称后通过空格指定。
在传统系统中,检查是否使用 `iptables-legacy` 或 `iptables-nft`。如果是 legacy,则需要创建文件 `/etc/modprobe.d/ip6table_raw.conf`,内容如下:
```
options ip6table_raw raw_before_defrag=1
```
在某些传统发行版中,可以通过 `update-alternatives --config ip6tables` 更改当前的 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 或更低。
使用 iptables 和 NAT 时,似乎无法在 NAT 之后挂载队列处理程序。
数据包带着内部网络的源地址进入 nfqws,然后被分片,不再由 NAT 处理。
就这样带着 192.168.x.x 的 src ip 进入外部网络。因此,该方法无效。
看来唯一可行的方法是放弃 iptables 并使用 nftablesHook 优先级必须为 101 或更高。
### 多重策略
**nfqws** 能够对不同的请求做出不同的反应,并应用不同的欺骗策略。
这是通过支持多个欺骗配置文件 来实现的。
配置文件在命令行中通过参数 `--new` 分隔。第一个配置文件是自动创建的,不需要 `--new`。每个配置文件都有一个过滤器。默认为空,意味着配置文件满足任何条件。
过滤器可以包含硬性参数:IP 协议版本、ipset 和 TCP/UDP 端口。
即使在零阶段去同步化(此时主机和 L7 尚未知晓)也能明确识别它们。
主机列表和应用层协议 (L7) 可作为软过滤器。
L7 协议通常在第一个包含数据的数据包之后才能知晓。
当请求到达时,按从第一个到最后一个的顺序检查配置文件,直到找到第一个与过滤器匹配的项。
首先检查硬性过滤器参数。如果不匹配,立即跳转到下一个配置文件。
如果某个配置文件满足硬性过滤器和 L7 过滤器并包含 auto-hostlist,则立即选中。
如果配置文件满足硬性过滤器和 L7 过滤器,并定义了主机列表,而我们还没有主机名,则跳转到下一个配置文件。否则,检查该配置文件的主机列表。
如果主机名符合列表,则选中该配置文件。否则,跳转到下一个。
可能会发生这样的情况:在获取主机名或识别 L7 协议之前,连接使用一个配置文件,而在确定这些参数后,配置文件会动态改变。这可能发生两次——在确定 L7 和主机名时。通常,这可以在一个步骤中完成,因为 L7 和主机通常可以通过一个数据包得知。
因此,如果您有零阶段欺骗参数,请仔细考虑切换策略时可能发生的情况。
请查看 debug 日志以更好地了解 nfqws 的行为。
配置文件编号从 1 到 N。最后创建一个编号为 0 的空配置文件。
当任何过滤器条件都不匹配时使用它。
### WIFI 过滤
Wifi 网络名称与 wifi 适配器的网络接口没有任何关系。
只有一个接口,可以连接到任何网络。不同网络使用不同策略。
来自网络 A 的策略不适用或破坏网络 B。该怎么办?
可以手动启动和停止 nfqws 实例。但也可以采用其他方法。
在 Windows 版本的 winws 中,有一个全局过滤器 `--ssid-filter`。
它根据任何适配器是否连接到特定 wifi 网络来启用或禁用 winws 实例。
不考虑路由。这种方法可行,因为可以将多个 winws 实例挂载到 windivert 上的重叠过滤器。
当切换 wifi 网络时,一些将启用,另一些将禁用。
对于 Linux,采用不同的解决方案。过滤器 `--filter-ssid` 属于特定配置文件。
无法将多个 nfqws 实例挂载到同一队列,也无法将同一流量导向多个队列。
从队列连接和断开不同实例涉及它们之间的同步复杂性。
因此,应由一个实例处理流量,并且它必须能够处理不同的 wifi 网络。
这正是 `--filter-ssid` 参数所实现的。它接收一个用逗号分隔的 wifi 网络名称 (SSID) 列表,类似于 winws 的 `--ssid-filter`。
在选择配置文件时,重要的是特定处理的数据包去向。到哪个接口。或者如果数据包被视为传入,则来自哪个接口。
因此,即使您的部分流量去往一个网络,部分去往另一个,还有部分根本不通过 wifi,所有这些都可以配置。
扫描所有 wifi 接口,构建 interface->SSID 列表。它随着数据包的到来而更新,但频率不超过每秒 1 次。
### NFQWS 的 IPTABLES
用于针对 TCP 连接中第一个数据包进行攻击的 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 不监控 keep-alive 会话中的所有 HTTP 请求时,使用此变体。
如果它监控,我们仅重定向 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 能够自行识别标记的数据包,但在使用 connbytes 时,iptables 中的 mark 过滤器是必需的,以防止数据包顺序改变。队列处理是一个延迟过程。
如果内核有数据包要在队列外发送,它会立即发送。
去同步化时数据包正确顺序的改变会破坏整个思路。
此外,在从 nfqws 发送大量数据包且缺少 mark 过滤器的情况下,曾观察到死锁。
进程可能挂起。因此,可以认为在 ip/nf tables 中使用 mark 过滤器是强制性的。
为什么是 `--connbytes 1:6`:
* 1 - 用于 0 阶段去同步化方法和 conntrack 的正常工作
* 2 - 有时数据在 3-way handshake 的第 3 个数据包中
* 3 - 接收单个请求数据包的标准情况
* 4-6 - 用于重传或跨多个数据包的长请求(例如带有 kyber 的 TLSClientHello)
对于 autottl 模式,必须重定向传入的 `SYN,ACK` 数据包或连接的第一个数据包(通常是一样的)。
对于 autohostlist 模式,需要传入的 RST 和 HTTP 重定向。
可以基于 TCP flags 构建 `SYN,ACK` 过滤器,并使用 u32 模块查找 HTTP 重定向特征模式,但使用 connbytes 提取几个初始传入数据包更简单。
`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 而不切换到 TCP 的情况下可能发生的 QUIC Initial 重传。
同时也是为了 QUIC 的 autohostlist 工作。但不建议对 QUIC 使用 autohostlist。
### NFQWS 的 NFTABLES
可以从基本配置开始。
```
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(避免俄罗斯 DPI 发送的 RST,ACK 数据包中错误的 ACK 序号)
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
如果您的设备支持硬件加速,iptables 可能无法工作。
启用 offloading 后,数据包不会经过常规的 netfilter 路径。必须禁用它或对其进行选择性控制。
较新的内核支持软件流卸载。
经过 SFO 的数据包也会绕过 iptables 的大部分机制。启用 SFO 时,DNAT/REDIRECT (tpws) 有效。
这些连接被排除在 offloading 之外。但是,其余连接通过 SFO,因此 NFQUEUE 仅在连接放入 flowtable 之前触发。实际上,这意味着 nfqws 的几乎所有功能都将失效。
Offload 通过 iptables 中的特殊 target `FLOWOFFLOAD` 或 nftables 中的 flowtable 启用。
不必使所有流量都通过 offload。
tpws 在设计上就绕过了 offload,而对于 nfqws,只需要 TCP 连接或 UDP 会话的前几个数据包即可。
在会话被导向 offload 之前,它通过完整的 netfilter 进行常规处理。
一旦任何传入或传出数据包触发了 offload 规则,整个会话将最终离开 netfilter 进入 offload。
因此,zapret 脚本获取它们为 NFQUEUE 创建的规则,并从中创建豁免规则,防止会话过早进入 offload,然后“释放”它。
此时,不允许传入数据包启动 offload,触发者仅为传出数据包。
该方案实际上对速度没有负面影响,同时满足了 nfqws 的需求并简化了表规则。
OpenWrt 不提供选择性控制 offload 的功能,因此 zapret 脚本支持自己的选择性控制系统。
iptables target `FLOWOFFLOAD` 是 OpenWrt 的专有发明。
nftables 中的 offload 控制在基本 Linux 内核中实现,无需补丁。
nftables 是在经典 Linux 上启用 offload 的唯一方法。
### 硬件特性
在 MediaTek 设备上发现了两个问题。
MediaKit 以太网驱动程序在硬件级别丢弃校验和无效的 TCP 和 UDP 数据包,无法禁用。
因此,通过路由器的 badsum 欺骗将不起作用,但从路由器发起的则可以。
MediaKit 的另一个问题影响以太网和无线网络,当启用 offload rx-gro-list 时,该问题在 UDP 上显现。
没有 nfqueue 时一切正常。一旦出现 nfqueue,部分数据包就会丢失。
在使用 kyber 进行 QUIC 欺骗时尤为明显。
此代码需要在 LAN 接口启动且所有网桥成员已加入网桥后调用。
可以使用 `/etc/hotplug.d/iface` 中的钩子。需要安装 `ethtool`。
MediaKit 问题已在 MT7621 (TP-Link Archer C6U v1) 和 MT7981 (Xiaomi AX3000T) 上确认。
其他芯片组可能也存在此问题,也可能没有。缺乏更广泛的统计数据。
### 服务器端欺骗
这也是可能的。
nfqws 专为客户端攻击设计,因此它根据 TCP 连接建立中的角色来识别正向和反向流量。
如果通过 SYN,则源 IP 为客户端。如果通过 SYN,ACK,则源 IP 为服务器。
对于 UDP,客户端被视为通过两个 IP-Port 组合的第一个数据包的源 IP。
在服务器上,接收到的流量被视为客户端流量,发出的流量被视为服务器流量。
`--wsize` 在任何情况下都有效,既可以在客户端使用,也可以在服务器上使用。
其余技术仅在 nfqws 将流量视为客户端流量时有效。
因此,要将它们应用于从服务器发出的流量,需要通过参数 `--ctrack-disable` 禁用 conntrack。
如果在 conntrack 中找不到数据包,则将其视为客户端数据包处理。
大多数协议将无法识别,因为其识别系统是基于客户端数据包内容的。
要使用 `fake` 或 `multisplit` 等技术,需要使用 `--dpi-desync-any-protocol` 配合 connbytes 限制器或基于数据包内容或其头部的限制器。
start/cutoff 不可用,因为它们依赖于 conntrack。
`synack-split` 技术允许将 TCP SYN,ACK 段拆分为单独的 SYN 和 ACK 部分。
作为响应,客户端发送 SYN,ACK,这通常是服务器的特征。
某些 DPI 的算法可能会因此中断,从而停止封锁被禁止的内容。
这里详细描述了什么是 [split handshake](https://nmap.org/misc/split-handshake.pdf)。
流量重定向通常基于源端口号和 original 方向。
original 是从系统发出的流量,reply 是传入的。
## tpws
tpws 是透明代理。
```
@|$ ; читать конфигурацию из файла. опция должна быть первой. остальные опции игнорируются.
--debug=0|1|2|syslog|@ ; 0,1,2 = логирование на косоль : 0=тихо, 1(default)=подробно, 2=отладка.
--debug-level=0|1|2 ; указать уровень логирования для syslog и @
--dry-run ; проверить опции командной строки и выйти. код 0 - успешная проверка.
--version ; вывести версию и выйти
--daemon ; демонизировать прогу
--pidfile= ; сохранить PID в файл
--user= ; менять 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= ; слушать на первом ipv4 интерфейса iface
--bind-iface6= ; слушать на первом ipv6 интерфейса iface
--bind-wait-ifup= ; ждать до N секунд появления и поднятия интерфейса
--bind-wait-ip= ; ждать до N секунд получения IP адреса (если задан --bind-wait-ifup - время идет после поднятия интерфейса)
--bind-wait-ip-linklocal=
; имеет смысл только при задании --bind-wait-ip
; --bind-linklocal=unwanted : согласиться на LL после N секунд
; --bind-linklocal=prefer : согласиться на global address после N секунд
--bind-wait-only ; подождать все бинды и выйти. результат 0 в случае успеха, иначе не 0.
--connect-bind-addr ; с какого адреса подключаться во внешнюю сеть. может быть ipv4 или ipv6 адрес
; если указан ipv6 link local, то требуется указать с какого он интерфейса : fe80::1%br-lan
; опция может повторяться для v4 и v6 адресов
; опция не отменяет правил маршрутизации ! выбор интерфейса определяется лишь правилами маршрутизации, кроме случая v6 link local.
--socks ; вместо прозрачного прокси реализовать socks4/5 proxy
--no-resolve ; запретить ресолвинг имен через socks5
--resolve-threads ; количество потоков ресолвера
--port= ; на каком порту слушать
--maxconn= ; максимальное количество соединений от клиентов к прокси
--maxfiles= ; макс количество файловых дескрипторов (setrlimit). мин требование (X*connections+16), где X=6 в tcp proxy mode, X=4 в режиме тамперинга.
; стоит сделать запас с коэффициентом как минимум 1.5. по умолчанию maxfiles (X*connections)*1.5+16
--max-orphan-time= ; если вы запускаете через tpws торрент-клиент с множеством раздач, он пытается установить очень много исходящих соединений,
; большая часть из которых отваливается по таймауту (юзера сидят за NAT, firewall, ...)
; установление соединения в linux может длиться очень долго. локальный конец отвалился, перед этим послав блок данных,
; tpws ждет подключения удаленного конца, чтобы отослать ему этот блок, и зависает надолго.
; настройка позволяет сбрасывать такие подключения через N секунд, теряя блок данных. по умолчанию 5 сек. 0 означает отключить функцию
; эта функция не действует на успешно подключенные ранее соединения
--local-rcvbuf= ; SO_RCVBUF для соединений client-proxy
--local-sndbuf= ; SO_SNDBUF для соединений client-proxy
--remote-rcvbuf= ; SO_RCVBUF для соединений proxy-target
--remote-sndbuf= ; SO_SNDBUF для соединений proxy-target
--nosplice ; не использовать splice на linux системах
--skip-nodelay ; не устанавливать в исходящих соединения TCP_NODELAY. несовместимо со split.
--local-tcp-user-timeout= ; таймаут соединений client-proxy (по умолчанию : 10 сек, 0 = оставить системное значение)
--remote-tcp-user-timeout= ; таймаут соединений proxy-target (по умолчанию : 20 сек, 0 = оставить системное значение)
--fix-seg= ; исправлять неудачи tcp сегментации ценой задержек для всех клиентов и замедления. ждать до N мс. по умолчанию 30 мс.
--ipcache-lifetime= ; время жизни записей кэша IP в секундах. 0 - без ограничений.
--ipcache-hostname=[0|1] ; 1 или отсутствие аргумента включают кэширование имен хостов для применения в стратегиях нулевой фазы
--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=|0xHEX ; переопределить байт OOB. по умолчанию 0x00.
--hostcase ; менять регистр заголовка "Host:". по умолчанию на "host:".
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--hostdot ; добавление точки после имени хоста : "Host: kinozal.tv."
--hosttab ; добавление табуляции после имени хоста : "Host: kinozal.tv\t"
--hostnospace ; убрать пробел после "Host:"
--hostpad= ; добавить паддинг-хедеров общей длиной перед Host:
--domcase ; домен после Host: сделать таким : TeSt.cOm
--methodspace ; добавить пробел после метода : "GET /" => "GET /"
--methodeol ; добавить перевод строки перед методом : "GET /" => "\r\nGET /"
--unixeol ; конвертировать 0D0A в 0A и использовать везде 0A
--tlsrec=N|-N|marker+N|marker-N ; разбивка TLS ClientHello на 2 TLS records на указанной позиции. Минимальное смещение - 6.
--mss= ; установить MSS для клиента. может заставить сервер разбивать ответы, но существенно снижает скорость
--tamper-start=[n] ; начинать дурение только с указанной байтовой позиции или номера блока исходяшего потока (считается позиция начала принятого блока)
--tamper-cutoff=[n] ; закончить дурение на указанной байтовой позиции или номере блока исходящего потока (считается позиция начала принятого блока)
--hostlist= ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются, если хост не начинается с '^'.
; в файле должен быть хост на каждой строке.
; список читается при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
; при изменении времени модификации файла он перечитывается автоматически по необходимости
; список может быть запакован в gzip. формат автоматически распознается и разжимается
; списков может быть множество. пустой общий лист = его отсутствие
; хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello.
--hostlist-domains= ; фиксированный список доменов через зяпятую. можно использовать # в начале для комментирования отдельных доменов.
--hostlist-exclude= ; не применять дурение к доменам из листа. может быть множество листов. схема аналогична include листам.
--hostlist-exclude-domains= ; фиксированный список доменов через зяпятую. можно использовать # в начале для комментирования отдельных доменов.
--hostlist-auto= ; обнаруживать автоматически блокировки и заполнять автоматический hostlist (требует перенаправления входящего трафика)
--hostlist-auto-fail-threshold= ; сколько раз нужно обнаружить ситуацию, похожую на блокировку, чтобы добавить хост в лист (по умолчанию: 3)
--hostlist-auto-fail-time= ; все эти ситуации должны быть в пределах указанного количества секунд (по умолчанию: 60)
--hostlist-auto-debug= ; лог положительных решений по autohostlist. позволяет разобраться почему там появляются хосты.
--new ; начало новой стратегии (новый профиль)
--skip ; не использовать этот профиль . полезно для временной деактивации профиля без удаления параметров.
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. поддерживается список через запятую.
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; фильтр протокола L6-L7. поддерживается несколько значений через запятую.
--ipset= ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-ip= ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
--ipset-exclude= ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-exclude-ip= ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
```
### TPWS 中的 TCP 分段
tpws 和 nfqws 一样,支持请求的多重分段。分割位置在 `--split-pos` 中设置。
通过逗号指定标记。标记说明请参见 [nfqws](#tcp-сегментация) 部分。
在应用层,通常没有保证的方法让内核在特定位置切分数据块。操作系统在每个套接字都有发送缓冲区 (SNDBUF)。
如果套接字启用了 TCP_NODELAY 选项且缓冲区为空,则每次 send 都会导致发送一个单独的 IP 数据包,或者如果数据块无法容纳在一个 IP 数据包中,则发送一组数据包。
但是,如果在 send 时刻缓冲区中还有未发送的数据,操作系统会将数据附加到其中,不会单独发送。但在这种情况下,也无法保证某个消息块位于数据包开头,而这正是 DPI 所关注的。
分割将根据 MSS 进行,MSS 取决于传出接口的 MTU。
因此,查看 TCP 数据包数据字段开头的 DPI 无论如何都会被破坏。
HTTP 协议属于请求-响应协议。新消息仅在服务器收到请求并完全返回响应后发送。这意味着请求实际上不仅已发送,而且已被对方接收,因此发送缓冲区为空,接下来的 2 次 send 将导致数据段通过不同的 IP 数据包发送。
因此,tpws 仅通过单独的 send 调用来保证分割,如果分割成不太多的部分且不是太小的连续部分,这通常很可靠。
在后一种情况下,Linux 可能仍会合并某些部分,导致实际分段与指定的分割位置不一致。其他操作系统在此方面的行为更具可预测性。未发现自发合并。
因此,不要滥用 split,尤其是较小的相邻数据包。
实践表明,如果分割数量超过一个,可能会出现问题。
有些系统在多达 8 个 split 时结果稳定,有些则在 2 个 split 后就开始出现问题。
如果不属于大规模流传输的一部分,一个 split 是稳定的。
如果分段失败,将输出消息 `WARNING ! segmentation failed`。
如果您看到此消息,这是减少分割位置数量的理由。
如果这不是选项,对于 Linux 内核 >=4.6,有参数 `--fix-seg`。它允许在发送下一部分之前等待发送完成。
但此选项破坏了异步事件处理模型。在期间,所有其他连接都不被处理并短暂挂起。实际上,这可能只是很小的等待——不到 10 毫秒。
仅在进行 split 且确实需要等待时才执行。
不建议在高负载系统中使用此选项。但对于家庭使用,可能适用,您甚至不会注意到这些延迟。
如果在信息到达速度快于发送速度时尝试使用 `--split-any-protocol` 对大规模传输进行 split,若没有 `--fix-seg`,分段错误将源源不断地流出。
在没有 `--tamper-start` 和 `--tamper-cutoff` 限制器的情况下处理大规模流通常没有意义。
tpws 在套接字级别工作,因此无法容纳在 1 个数据包中的长请求(带有 kyber 的 TLS)将作为整块接收。
对于每个分割部分,它进行单独的 `send()` 调用。但如果大小超过 MTU,操作系统无法在单个数据包中发送数据。
如果段过大,操作系统会将其进一步切成更小的块。结果应类似于 nfqws。
`--disorder` 强制从第一个开始每隔一个数据包发送 TTL=1。
所有偶数数据包立即到达服务器。操作系统对其余数据包进行重传,然后到达。
这本身会产生额外的延迟(Linux 中第一次重传为 200 毫秒)。
在套接字版本中,没有其他方法可以实现 disorder。
6 个段的最终顺序变为 `2 4 6 1 3 5`。
`--oob` 在第一个分割段之后发送 1 个字节的带外数据。在每个分割段中显示 `oob` 被证明是不可靠的。
服务器在套接字中接收 oob。
`oob` 和 `disorder` 的组合仅在 Linux 中可能。其他操作系统无法处理这种情况。URG 标志在重传期间丢失。
服务器在套接字中接收 oob。在除 Linux 之外的操作系统上组合这些参数会在启动阶段导致错误。
### TLSREC
`--tlsrec` 允许在单个 TCP 段内将 TLS ClientHello 切割为 2 个 TLS 记录。可以使用标准标记机制设置相对位置。
`--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。
该方案可能会显着降低速度,并且不适用于所有网站。
仅在某些情况下与主机列表过滤器兼容,即在应用欺骗时可以获知主机名的情况。
如果浏览器也支持 TLS1.3,将此选项应用于 TLS1.3 网站只会适得其反。
但是无法自动知道何时应用何时不应用,因为 MSS 仅在数据交换之前的 3-way handshake 中出现,而 TLS 版本只能通过服务器的响应获知,这可能导致 DPI 反应。
仅在没有更好选择或针对特定资源时使用。
对于 HTTP 没有使用意义,因此请建立单独的 desync 配置文件并按端口 443 过滤。
仅适用于 Linux,不适用于 BSD 和 MacOS。
### 其他欺骗参数
参数 `--hostpad=` 在 `Host:` 之前添加指定字节数的填充头。
如果 `` 大小太大,则将其拆分为 2K 的不同头。
HTTP 请求的总接收缓冲区为 64K,不支持更大的填充,HTTP 服务器也不再接受此类请求。
对执行有限缓冲区 TCP 重组的 DPI 有用。
如果技术有效,经过一定数量的字节后,HTTP 请求将开始到达网站。
如果此时关键填充大小约为 MTU,则很可能 DPI 不执行数据包重组,最好使用标准的 TCP 分段选项。
如果确实执行了重组,则关键大小约为 DPI 缓冲区大小。可能是 4K 或 8K,或者其他值。
### 多重策略
工作方式类似于 **nfqws**,但有一些区别。
没有参数 `--filter-udp`,因为 **tpws** 不支持 UDP。
零阶段方法(`--mss`)仅在两种情况下可以按主机列表工作:
如果使用 socks 模式并通过代理进行远程主机解析,或者使用 [IP 缓存](#кэш-ip) 系统记录 IP->主机名对应关系。
在同一模式下,设置的可用性可能取决于客户端是否应用远程解析。这可能并不明显。在一个程序中有效,在另一个程序中无效。
如果您使用带主机列表的配置文件,并且需要 mss 始终生效,请在带主机列表的配置文件中指定 mss,如果尚无无主机列表的配置文件则创建一个,并在其中再次指定 mss。
那么无论如何都会执行 mss。
如果您需要按主机列表使用 mss,请仅在带主机列表的配置文件中指定 `--mss`,并确保具备在此类模式下工作所需的任何条件。
使用 `curl --socks5` 和 `curl --socks5-hostname` 测试您的策略。
查看 `--debug` 输出以确保设置正确。
### 服务参数
`--debug` 允许将详细操作日志输出到控制台、syslog 或文件。
选项的顺序可能很重要。最好在开头指定 `--debug`。
选项按顺序分析。如果在检查选项时出错,而尚未分析 `--debug`,则消息不会输出到文件或 syslog。
`--debug=0|1|2` 允许在一个参数中启用控制台日志记录并指定级别。
保留是为了与旧版本兼容。要在 syslog 或 file 模式下选择级别,请使用单独的参数 `--debug-level`。如果在这些模式下未通过 `--debug-level` 指定级别,则自动分配级别 1。
记录到文件时,进程不会保持文件打开。每次记录都会打开然后关闭文件。
因此可以随时删除文件,下次写入日志时会重新创建。
但请注意,如果您以 root 身份启动进程,则 UID 将更改为非 root。
开始时,日志文件的所有者会更改,否则无法写入。如果随后删除文件,并且进程无权在其目录中创建文件,则日志将停止。
最好使用 truncate 而不是删除。
在 shell 中可以通过命令 `: >filename` 完成
tpws 可以绑定到多个接口和 IP 地址(最多 32 个)。
端口始终只有一个。
参数 `--bind-iface*` 和 `--bind-addr` 创建新绑定。
其余参数 `--bind-*` 属于最后一个绑定。
要绑定到所有 IPv4,指定 `--bind-addr "0.0.0.0"`,所有 IPv6 - `"::"`。`--bind-addr=""` - 绑定到所有 IPv4 和 IPv6。
链路本地 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
```
如果未指定绑定,则默认绑定到所有接口的所有地址。
要绑定到特定的链路本地地址,执行:`--bind-iface6=fe80::aaaa:bbbb:cccc:dddd%iface-name`
当需要从接口获取 IP 但接口尚不存在、未启动或未配置时,参数 `--bind-wait*` 可能有帮助。
在不同系统中,捕获 ifup 事件的方式不同,并且不能保证接口已获得特定类型的 IP 地址。
通常,没有单一的机制可以挂载到“接口 X 上出现链路本地地址”之类的事件上。
要在接口未配置时绑定到已知 IP,需要执行:`--bind-addr=192.168.5.3 --bind-wait-ip=20`
在透明模式下,可以绑定到任何不存在的地址,在 socks 模式下 - 只能绑定到存在的地址。
参数 rcvbuf 和 sndbuf 允许为本地和远程连接设置 setsockopt SO_RCVBUF SO_SNDBUF。
当 tpws 在不进行欺骗的情况下使用时,`--skip-nodelay` 可用于将 MTU 调整为运行 tpws 的系统的 MTU。
这对于隐藏 VPN 的使用可能有用。较低的 MTU 是检测可疑连接的方法之一。使用 TCP 代理,您的连接与网关本身建立的连接无法区分。
`--local-tcp-user-timeout` 和 `--remote-tcp-user-timeout` 设置客户端-代理和代理-服务器连接的超时值(秒)。
此超时对应于 Linux 套接字选项 TCP_USER_TIMEOUT。超时是指缓冲数据未传输或未收到对传输数据的确认 (ACK) 的时间。
此超时与仅因没有数据传输而导致的通过套接字无传输时间无关。有助于缩短挂起连接的关闭时间。
仅支持 Linux 和 MacOS。
`--socks` 模式不需要提升权限(绑定到特权端口 1..1023 除外)。
支持无认证的 socks 4 和 5。协议版本自动识别。
禁止连接到运行 tpws 的同一设备的 IP,包括 localhost。
socks5 允许远程解析主机 (curl : --socks5-hostname firefox : socks_remote_dns=true)。
tpws 使用多线程解析器池异步支持此功能,不会阻塞其他连接的处理。线程数根据 `--maxconn` 自动确定,但也可以通过参数 `--resolver-threads` 手动设置。
Socks 请求暂停,直到域在其中一个解析器线程中解析为 IP。如果所有线程都忙,等待时间可能更长。
如果指定了 `--no-resolve` 参数,则禁止按主机名连接,并且不创建解析器池。
从而节省资源。
### TPWS 的 IPTABLES
要将 TCP 连接重定向到透明代理,使用以下命令:
```
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
```
第一条命令用于来自系统本身的连接,第二条用于通过路由器的连接。
DNAT 到 localhost 在 OUTPUT 链中有效,但在 PREROUTING 链中无效,除非启用 route_localnet 参数:
`sysctl -w net.ipv4.conf.<内部接口>.route_localnet=1`
可以使用 `-j REDIRECT --to-port 988` 代替 DNAT,但是,在这种情况下,透明代理进程必须监听传入接口的 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 работает без изменений.
### TPWS 的 NFTABLES 配置
Базовая конфигурация :
```
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
```
## 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 - гораздо лучше.
## mdig
Программа предназначена для многопоточного ресолвинга больших листов через системный DNS.
Она берет из stdin список доменов и выводит в stdout результат ресолвинга. Ошибки выводятся в stderr.
```
--threads= ; количество потоков. по умолчанию 1.
--family=<4|6|46> ; выбор семейства IP адресов : ipv4, ipv6, ipv4+ipv6
--verbose ; дебаг-лог на консоль
--stats=N ; выводить статистику каждые N доменов
--log-resolved= ; сохранять успешно отресолвленные домены в файл
--log-failed= ; сохранять неудачно отресолвленные домены в файл
--dns-make-query= ; вывести в stdout бинарный DNS запрос по домену. если --family=6, запрос будет AAAA, иначе A.
--dns-parse-query ; распарсить бинарный DNS ответ и выдать все ivp4 и ipv6 адреса из него в stdout
```
Параметры `--dns-make-query` и `--dns-parse-query` позволяют провести ресолвинг одного домена через произвольный канал.
Например, следующим образом можно выполнить DoH запрос, используя лишь mdig и curl :
```
mdig --family=6 --dns-make-query=rutracker.org | curl --data-binary @- -H "Content-Type: application/dns-message" https://cloudflare-dns.com/dns-query | mdig --dns-parse-query
```
## 获取被屏蔽 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 (собственная разработка).
3. `ipset/get_reestr_preresolved.sh`. то же самое, что и 2), только берется уже заресолвленый список
со стороннего ресурса.
4. `ipset/get_reestr_preresolved_smart.sh`. то же самое, что и 3), с добавлением всего диапазона некоторых
автономных систем (прыгающие IP адреса из cloudflare, facebook, ...) и некоторых поддоменов блокируемых сайтов
Cкрипты с названием `get_antifilter_*` оперируют списками адресов и масок подсетей с сайтов antifilter.network и antifilter.download :
5. `ipset/get_antifilter_ip.sh`. получает лист https://antifilter.download/list/ip.lst.
6. `ipset/get_antifilter_ipsmart.sh`. получает лист https://antifilter.network/download/ipsmart.lst.
умная суммаризация отдельных адресов из ip.lst по маскам от /32 до /22
7. `ipset/get_antifilter_ipsum.sh`. получает лист https://antifilter.download/list/ipsum.lst.
суммаризация отдельных адресов из ip.lst по маске /24
8. `ipset/get_antifilter_ipresolve.sh`. получает лист https://antifilter.download/list/ipresolve.lst.
пре-ресолвленный список, аналогичный получаемый при помощи get_reestr_resolve. только ipv4.
9. `ipset/get_antifilter_allyouneed.sh`. получает лист https://antifilter.download/list/allyouneed.lst.
Суммарный список префиксов, созданный из ipsum.lst и subnet.lst.
10. `ipset/get_refilter_ipsum.sh`.
Список берется отсюда : https://github.com/1andrevich/Re-filter-lists
Все варианты рассмотренных скриптов автоматически создают и заполняют ipset.
Варианты 2-10 дополнительно вызывают вариант 1.
11. `ipset/get_config.sh`. этот скрипт вызывает то, что прописано в переменной GETLIST из файла config
Если переменная не определена, то ресолвятся лишь листы для ipset nozapret/nozapret6.
Листы РКН все время изменяются. Возникают новые тенденции. Требования к RAM могут меняться.
Поэтому необходима нечастая, но все же регулярная ревизия что же вообще у вас происходит на роутере.
Или вы можете узнать о проблеме лишь когда у вас начнет постоянно пропадать wifi, и вам придется
его перезагружать каждые 2 часа (метод кувалды).
Самые щадящие варианты по RAM - `get_antifilter_allyouneed.sh`, `get_antifilter_ipsum.sh`, `get_refilter_*.sh`.
Листы `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=- отключает перезагрузку листов.
## 按域名过滤
Альтернативой ipset является использование tpws или nfqws со списком доменов.
Оба демона принимают неограниченное количество листов include (`--hostlist`) и exclude (`--hostlist-exclude`).
Прежде всего проверяются exclude листы. При вхождении в них происходит отказ от дурения.
Далее при наличии include листов проверяется домен на вхождение в них. При невхождении в список отказ от дурения.
Если все include листы пустые, это приравнивается к отсутствию include листов. Ограничениеает работать.
В иных случаях происходит дурение.
Нет ни одного списка - дурение всегда.
Есть только exclude список - дурение всех, кроме.
Есть только include список - дурение только их.
Есть оба - дурение только include, кроме exclude.
В системе запуска это обыграно следующим образом.
Присутствуют 2 include списка :
`ipset/zapret-hosts-user.txt.gz` или `ipset/zapret-hosts-user.txt`,
`ipset/zapret-hosts.txt.gz` или `ipset/zapret-hosts.txt`
и 1 exclude список
`ipset/zapret-hosts-user-exclude.txt.gz` или `ipset/zapret-hosts-user-exclude.txt`
При режимах фильтрации `MODE_FILTER=hostlist` или `MODE_FILTER=autohostlist` система запуска передает **nfqws** или **tpws** все листы, файлы которых присутствуют.
Передача происходит через замену маркеров `` и `` на реальные параметры `--hostlist`, `--hostlist-exclude`, `--hostlist-auto`.
Если вдруг листы include присутствуют, но все они пустые, то работа аналогична отсутствию include листа.
Файл есть, но несмотря на это дурится все, кроме exclude.
Если вам нужен именно такой режим - не обязательно удалять `zapret-hosts-users.txt`. Достаточно сделать его пустым.
Поддомены учитываются автоматически. Например, строчка "ru" вносит в список "\*.ru". Строчка "\*.ru" в списке не сработает.
Можно использовать символ `^` в начале хоста, чтобы отказаться от автоматического учета поддоменов.
Список доменов РКН может быть получен скриптами
```
ipset/get_reestr_hostlist.sh
ipset/get_antizapret_domains.sh
ipset/get_reestr_resolvable_domains.sh
ipset/get_refilter_domains.sh
```
Он кладется в `ipset/zapret-hosts.txt.gz`.
При изменении времени модификации или размера файлов списки перечитываются автоматически.
После неатомарных операций изменения можно послать tpws/nfqws сигнал HUP для принудительной перечитки всех листов.
При фильтрации по именам доменов демон должен запускаться без фильтрации по ipset.
tpws и nfqws решают нужно ли применять дурение в зависимости от хоста, полученного из протокола прикладного уровня (http, tls, quic).
При использовании больших списков, в том числе списка РКН, оцените объем RAM на роутере !
Если после запуска демона RAM под завязку или случаются oom, значит нужно отказаться от таких больших списков.
## autohostlist 过滤模式
Этот режим позволяет проанализировать как запросы со стороны клиента, так и ответы от сервера.
Если хост еще не находится ни в каких листах и обнаруживается ситуация, похожая на блокировку,
происходит автоматическое добавление хоста в список `autohostlist` как в памяти, так и в файле.
**nfqws** или **tpws** сами ведут этот файл.
Чтобы какой-то хост не смог попась в `autohostlist` используйте `hostlist-exclude`.
Если он все-же туда попал - удалите запись из файла вручную. Процессы автоматически перечитают файл.
**tpws**/**nfqws** сами назначают владельцем файла юзера, под которым они работают после сброса привилегий,
чтобы иметь возможность обновлять лист.
В случае **nfqws** данный режим требует перенаправления в том числе и входящего трафика.
Крайне рекомендовано использовать ограничитель `connbytes`, чтобы **nfqws** не обрабатывал гигабайты.
По этой же причине не рекомендуется использование режима на BSD системах. Там нет фильтра `connbytes`.
На linux системах при использовании nfqws и фильтра connbytes может понадобиться :
`sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1`
Было замечено, что некоторые DPI в России возвращают RST с неверным ACK. Это принимается tcp/ip стеком
linux, но через раз приобретает статус INVALID в conntrack. Поэтому правила с `connbytes` срабатывают
через раз, не пересылая RST пакет **nfqws**.
Как вообще могут вести себя DPI, получив "плохой запрос" и приняв решение о блокировке:
1. Зависание: просто отмораживается, блокируя прохождение пакетов по TCP каналу.
2. RST: отправляет RST клиенту и/или серверу
3. Редирект: (только для http) отправляет редирект на сайт-заглушку
4. Подмена сертификата: (только для https) полный перехват TLS сеанса с попыткой всунуть что-то
свое клиенту. Применяется нечасто, поскольку броузеры на такое ругаются.
**nfqws** и **tpws** могут сечь варианты 1-3, 4 они не распознают.
В силу специфики работы с отдельными пакетами или с TCP каналом tpws и nfqws распознают эти ситуации
по-разному.
Что считается ситуацией, похожей на блокировку :
1. **nfqws** Несколько ретрансмиссий первого запроса в TCP сеансе, в котором имеется host.
2. **nfqws,tpws** RST, пришедший в ответ на первый запрос с хостом.
3. **nfqws,tpws** HTTP редирект, пришедший в ответ на первый запрос с хостом, на глобальный адрес
с доменом 2 уровня, не совпадающим с доменом 2 уровня оригинального запроса.
4. **tpws** закрытие соединения клиентом после отправки первого запроса с хостом, если не было на него
ответа со стороны сервера. Это обычно случается по таймауту, когда нет ответа (случай "зависание").
Чтобы снизить вероятность ложных срабатываний, имеется счетчик ситуаций, похожих на блокировку.
Если за определенное время произойдет более определенного их количества, хост считается заблокированным
и заносится в `autohostlist`. По нему сразу же начинает работать стратегия по обходу блокировки.
Если в процессе счета вебсайт отвечает без признаков блокировки, счетчик сбрасывается.
Вероятно, это был временный сбой сайта.
На практике работа с данным режимом выглядит так.
Первый раз пользователь заходит на сайт и получает заглушку, сброс соединения или броузер подвисает,
вываливаясь по таймауту с сообщением о невозможности загрузить страницу.
Надо долбить F5, принуждая броузер повторять попытки. После некоторой попытки сайт
начинает работать, и дальше он будет работать всегда.
С этим режимом можно использовать техники обхода, ломающие значительное количество сайтов.
Если сайт не ведет себя как заблокированный, значит обход применен не будет.
В противном случае терять все равно нечего.
Однако, могут быть временные сбои сервера, приводящие к ситуации, аналогичной блокировке.
Могут происходить ложные срабатывания. Если такое произошло, стратегия может начать ломать
незаблокированный сайт. Эту ситуацию, увы, придется вам контролировать вручную.
Заносите такие домены в `ipset/zapret-hosts-user-exclude.txt`, чтобы избежать повторения.
Чтобы впоследствии разобраться почему домен был занесен в лист, можно включить `autohostlist debug log`.
Он полезен тем, что работает без постоянного просмотра вывода **nfqws** в режиме debug.
В лог заносятся только основные события, ведущие к занесению хоста в лист.
По логу можно понять как избежать ложных срабатываний и подходит ли вообще вам этот режим.
Можно использовать один `autohostlist` с множеством процессов. Все процессы проверяют время модификации файла.
Если файл был изменен в другом процессе, происходит его перечитывание.
Все процессы должны работать под одним uid, чтобы были права доступа на файл.
Скрипты `zapret` ведут `autohostlist` в `ipset/zapret-hosts-auto.txt`.
`install_easy.sh` при апгрейде `zapret` сохраняет этот файл.
Режим `autohostlist` включает в себя режим `hostlist`.
Можно вести `ipset/zapret-hosts-user.txt`, `ipset/zapret-hosts-user-exclude.txt`.
## 检查运营商
Перед настройкой нужно провести исследование какую бяку устроил вам ваш провайдер.
Нужно выяснить не подменяет ли он 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`.
Еще один эффективный вариант - использовать ресолвер от yandex 77.88.8.88 на нестандартном порту 1253.
Многие провайдеры не анализируют обращения к DNS на нестандартных портах.
`blockcheck` если видит подмену DNS автоматически переключается на DoH сервера.
Следует прогнать `blockcheck` по нескольким заблокированным сайтам и выявить общий характер блокировок.
Разные сайты могут быть заблокированы по-разному, нужно искать такую технику, которая работает на большинстве.
Чтобы записать вывод `blockcheck.sh` в файл, выполните: `./blockcheck.sh | tee /tmp/blockcheck.txt`.
Проанализируйте какие методы дурения DPI работают, в соответствии с ними настройте `/opt/zapret/config`.
Имейте в виду, что у провайдеров может быть несколько DPI или запросы могут идти через разные каналы
по методу балансировки нагрузки. Балансировка может означать, что на разных ветках разные DPI или
они находятся на разных хопах. Такая ситуация может выражаться в нестабильности работы обхода.
Дернули несколько раз curl. То работает, то connection reset или редирект. `blockcheck.sh` выдает
странноватые результаты. То split работает на 2-м. хопе, то на 4-м. Достоверность результата вызывает сомнения.
В этом случае задайте несколько повторов одного и того же теста. Тест будет считаться успешным только,
если все попытки пройдут успешно.
При использовании `autottl` следует протестировать как можно больше разных доменов. Эта техника
может на одних провайдерах работать стабильно, на других потребуется выяснить при каких параметрах
она стабильна, на третьих полный хаос, и проще отказаться.
`Blockcheck` имеет 3 уровня сканирования.
* `quick` - максимально быстро найти хоть что-то работающее.
* `standard` дает возможность провести исследование как и на что реагирует DPI в плане методов обхода.
* `force` дает максимум проверок даже в случаях, когда ресурс работает без обхода или с более простыми стратегиями.
Есть ряд других параметров, которые не будут спрашиваться в диалоге, но которые можно переопределить через
переменные.
```
CURL - замена программы curl
CURL_MAX_TIME - время таймаута curl в секундах
CURL_MAX_TIME_QUIC - время таймаута curl для quic. если не задано, используется значение CURL_MAX_TIME
CURL_MAX_TIME_DOH - время таймаута curl для DoH серверов
CURL_CMD=1 - показывать команды curl
CURL_OPT - дополнительные параметры curl. `-k` - игнор сертификатов. `-v` - подробный вывод протокола
CURL_HTTPS_GET=1 - использовать метод GET вместо HEAD для https
DOMAINS - список тестируемых доменов через пробел
IPVS=4|6|46 - тестируемые версии ip протокола
ENABLE_HTTP=0|1 - включить тест plain http
ENABLE_HTTPS_TLS12=0|1 - включить тест https TLS 1.2
ENABLE_HTTPS_TLS13=0|1 - включить тест https TLS 1.3
ENABLE_HTTP3=0|1 - включить тест QUIC
REPEATS - количество попыток тестирования
PARALLEL=0|1 - включить параллельные попытки. может обидеть сайт из-за долбежки и привести к неверному результату
SCANLEVEL=quick|standard|force - уровень сканирования
BATCH=1 - пакетный режим без вопросов и ожидания ввода в консоли
HTTP_PORT, HTTPS_PORT, QUIC_PORT - номера портов для соответствующих протоколов
SKIP_DNSCHECK=1 - отказ от проверки DNS
SKIP_IPBLOCK=1 - отказ от тестов блокировки по порту или IP
SKIP_TPWS=1 - отказ от тестов tpws
SKIP_PKTWS=1 - отказ от тестов nfqws/dvtws/winws
PKTWS_EXTRA, TPWS_EXTRA - дополнительные параметры nfqws/dvtws/winws и tpws, указываемые после основной стратегии
PKTWS_EXTRA_1 .. PKTWS_EXTRA_9, TPWS_EXTRA_1 .. TPWS_EXTRA_9 - отдельно дополнительные параметры, содержащие пробелы
PKTWS_EXTRA_PRE - дополнительные параметры для nfqws/dvtws/winws, указываемые перед основной стратегией
PKTWS_EXTRA_PRE_1 .. PKTWS_EXTRA_PRE_9 - отдельно дополнительные параметры, содержащие пробелы
SECURE_DNS=0|1 - принудительно выключить или включить DoH
DOH_SERVERS - список URL DoH через пробел для автоматического выбора работающего сервера
DOH_SERVER - конкретный DoH URL, отказ от поиска
UNBLOCKED_DOM - незаблокированный домен, который используется для тестов IP block
MIN_TTL,MAX_TTL - пределы тестов с TTL. MAX_TTL=0 отключает тесты.
MIN_AUTOTTL_DELTA,MAX_AUTOTTL_DELTA - пределы тестов с autottl по дельте. MAX_AUTOTTL_DELTA=0 отключает тесты.
SIMULATE=1 - включить режим симуляции для отладки логики скрипта. отключаются реальные запросы через curl, заменяются рандомным результатом.
SIM_SUCCESS_RATE= - вероятность успеха симуляции в процентах
```
Пример запуска с переменными:\
`SECURE_DNS=1 SKIP_TPWS=1 CURL_MAX_TIME=1 CURL=/tmp/curl ./blockcheck.sh`
**СКАН ПОРТОВ**\
Если в системе присутствует совместимый `netcat` (ncat от nmap или openbsd ncat. в OpenWrt по умолчанию нет),
то выполняется сканирование портов http или https всех IP адресов домена.
Если ни один IP не отвечает, то результат очевиден. Можно останавливать сканирование.
Автоматически оно не остановится, потому что netcat-ы недостаточно подробно информируют о причинах ошибки.
Если доступна только часть IP, то можно ожидать хаотичных сбоев, т.к. подключение идет к случайному адресу
из списка.
**ПРОВЕРКА НА ЧАСТИЧНЫЙ IP block**\
Под частичным блоком подразумевается ситуация, когда коннект на порты есть, но по определенному транспортному
или прикладному протоколу всегда идет реакция DPI вне зависимости от запрашиваемого домена.
Эта проверка так же не выдаст автоматического вердикта/решения, потому что может быть очень много вариаций.
Вместо этого анализ происходящего возложен на самого пользователя или тех, кто будет читать лог.
уть этой проверки в попытке дернуть неблокированный IP с блокированным доменом и наоборот, анализируя
при этом реакцию DPI. Реакция DPI обычно проявляется в виде таймаута (зависание запроса), connection reset
или http redirect на заглушку. Любой другой вариант скорее всего говорит об отсутствии реакции DPI.
В частности, любые http коды, кроме редиректа, ведущего именно на заглушку, а не куда-то еще.
На TLS - ошибки handshake без задержек.
Ошибка сертификата может говорить как о реакции DPI с MiTM атакой (подмена сертификата), так и
о том, что принимающий сервер неблокированного домена все равно принимает ваш TLS `handshake` с чужим доменом,
пытаясь при этом выдать сертификат без запрошенного домена. Требуется дополнительный анализ.
Если на заблокированный домен есть реакция на всех IP адресах, значит есть блокировка по домену.
Если на неблокированный домен есть реакция на IP адресах блокированного домена, значит имеет место блок по IP.
Соответственно, если есть и то, и другое, значит есть и блок по IP, и блок по домену.
Неблокированный домен первым делом проверяется на доступность на оригинальном адресе.
При недоступности тест отменяется, поскольку он будет неинформативен.
Если выяснено, что есть частичный блок по IP на DPI, то скорее всего все остальные тесты будут провалены
вне зависимости от стратегий обхода. Но бывают и некоторые исключения. Например, пробитие через `ipv6
option headers`. Или сделать так, чтобы он не мог распознать протокол прикладного уровня.
Дальнейшие тесты могут быть не лишены смысла.
**ПРИМЕРЫ БЛОКИРОВКИ ТОЛЬКО ПО ДОМЕНУ БЕЗ БЛОКА ПО IP**
```
> testing iana.org on it's original
!!!!! AVAILABLE !!!!!
> testing rutracker.org on 192.0.43.8 (iana.org)
curl: (28) Operation timed out after 1002 milliseconds with 0 bytes received
> testing iana.org on 172.67.182.196 (rutracker.org)
HTTP/1.1 409 Conflict
> testing iana.org on 104.21.32.39 (rutracker.org)
HTTP/1.1 409 Conflict
> testing iana.org on it's original ip
!!!!! AVAILABLE !!!!!
> testing rutracker.org on 192.0.43.8 (iana.org)
curl: (28) Connection timed out after 1001 milliseconds
> testing iana.org on 172.67.182.196 (rutracker.org)
curl: (35) OpenSSL/3.2.1: error:0A000410:SSL routines::ssl/tls alert handshake failure
> testing iana.org on 104.21.32.39 (rutracker.org)
curl: (35) OpenSSL/3.2.1: error:0A000410:SSL routines::ssl/tls alert handshake failure
> testing iana.org on it's original ip
!!!!! AVAILABLE !!!!!
> testing rutracker.org on 192.0.43.8 (iana.org)
HTTP/1.1 307 Temporary Redirect
Location: https://www.gblnet.net/blocked.php
> testing iana.org on 172.67.182.196 (rutracker.org)
HTTP/1.1 409 Conflict
> testing iana.org on 104.21.32.39 (rutracker.org)
HTTP/1.1 409 Conflict
> testing iana.org on it's original ip
!!!!! AVAILABLE !!!!!
> testing rutracker.org on 192.0.43.8 (iana.org)
curl: (35) Recv failure: Connection reset by peer
> testing iana.org on 172.67.182.196 (rutracker.org)
curl: (35) OpenSSL/3.2.1: error:0A000410:SSL routines::ssl/tls alert handshake failure
> testing iana.org on 104.21.32.39 (rutracker.org)
curl: (35) OpenSSL/3.2.1: error:0A000410:SSL routines::ssl/tls alert handshake failure
```
**ПРИМЕР ПОЛНОГО IP БЛОКА ИЛИ БЛОКА TCP ПОРТА ПРИ ОТСУТСТВИИ БЛОКА ПО ДОМЕНУ**
```
* port block tests ipv4 startmail.com:80
ncat -z -w 1 145.131.90.136 80
145.131.90.136 does not connect. netcat code 1
ncat -z -w 1 145.131.90.152 80
145.131.90.152 does not connect. netcat code 1
* curl_test_http ipv4 startmail.com
- checking without DPI bypass
curl: (28) Connection timed out after 2002 milliseconds
UNAVAILABLE code=28
- IP block tests (requires manual interpretation)
> testing iana.org on it's original ip
!!!!! AVAILABLE !!!!!
> testing startmail.com on 192.0.43.8 (iana.org)
HTTP/1.1 302 Found
Location: https://www.iana.org/
> testing iana.org on 145.131.90.136 (startmail.com)
curl: (28) Connection timed out after 2002 milliseconds
> testing iana.org on 145.131.90.152 (startmail.com)
curl: (28) Connection timed out after 2002 milliseconds
```
## 参数选择
Файл `/opt/zapret/config` используется различными компонентами системы и содержит основные настройки.
Его нужно просмотреть и при необходимости отредактировать.
На linux системах можно выбрать использовать `iptables` или `nftables`.
По умолчанию на традиционных linux выбирается `nftables`, если установлен nft.
На OpenWrt по умолчанию выбирается `nftables` на новых версиях с firewall4.
`FWTYPE=iptables`
На `nftables` можно отключить стандартную схему перехвата трафика после NAT и перейти на перехват до NAT.
Это сделает невозможным применение некоторых методов дурения на проходящем трафике как в случае с `iptables`.
nfqws начнет получать адреса пакетов из локальной сети и отображать их в логах.
`POSTNAT=0`
Существует 3 стандартных опции запуска, настраиваемых раздельно и независимо: `tpws-socks`, **tpws**, **nfqws**.
Их можно использовать как по отдельности, так и вместе. Например, вам надо сделать комбинацию
из методов, доступных только в **tpws** и только в **nfqws**. Их можно задействовать вместе.
**tpws** будет прозрачно локализовывать трафик на системе и применять свое дурение, **nfqws** будет дурить трафик,
исходящий с самой системы после обработки на **tpws**.
А можно на эту же систему повесить без параметров socks proxy, чтобы получать доступ к обходу блокировок через прокси.
Таким образом, все 3 режима вполне могут задействоваться вместе.
Так же безусловно и независимо, в добавок к стандартным опциям, применяются все custom скрипты в `init.d/{sysv,openwrt,macos}/custom.d`.
Однако, при комбинировании tpws и nfqws с пересечением по L3/L4 протоколам не все так просто , как может показаться на первый взгляд.
Первым всегда работает tpws, за ним - nfqws. На nfqws попадает уже "задуренный" трафик от tpws.
Получается, что дурилка дурит дурилку, и дурилка не срабатывает, потому что ее задурили.
Вот такой веселый момент. nfqws перестает распознавать протоколы и применять методы.
Некоторые методы дурения от tpws nfqws в состоянии распознать и отработать корректно, но большинство - нет.
Решение - использование `--dpi-desync-any-protocol` в nfqws и работа как с неизвестным протоколом.
Комбинирование tpws и nfqws является продвинутым вариантом, требующим глубокого понимания происходящего.
Очень желательно проанализировать действия nfqws по `--debug` логу. Все ли так, как вы задумали.
Одновременное использование tpws и nfqws без пересечения по L3/L4 (то есть nfqws - udp, tpws - tcp или nfqws - port 443, tpws - port 80 или nfqws - ipv4, tpws - ipv6) проблем не представляет.
`tpws-socks` требует настройки параметров **tpws**, но не требует перехвата трафика.
Остальные опции требуют раздельно настройки перехвата трафика и опции самих демонов.
Каждая опция предполагает запуск одного инстанса соответствующего демона. Все различия методов дурения
для `http`, `https`, `quic` и т.д. должны быть отражены через схему мультистратегий.
В этом смысле настройка похожа на вариант `winws` на Windows, а перенос конфигов не должен представлять больших сложностей.
Основное правило настройки перехвата - перехватывайте только необходимый минимум.
Любой перехват лишнего - это бессмысленная нагрузка на вашу систему.
Опции демонов `--ipset` использовать нужно с умом. Не стоит перехватывать весь трафик, чтобы потом по параметру --ipset
выделить лишь горстку IP. Это будет работать, но очень неэффективно с точки зрения нагрузки на систему.
Используйте `ipset`-ы режима ядра. При необходимости пишите и задействуйте `custom scripts`.
Но если у вас и так идет работа по всем IP, и нужно написать небольшую специализацию по IP, то --ipset вполне уместен.
Настройки демонов можно для удобства писать на нескольких строках, используя двойные или одинарные кавычки.
Чтобы задействовать стандартные обновляемые хост-листы из каталога `ipset`, используйте маркер .
Он будет заменен на параметры, соответствующие режиму MODE_FILTER, и будут подставлены реально существующие файлы.
Если MODE_FILTER не предполагает стандартного хостлиста, будет заменен на пустую строку.
Стандартные хостлисты следует вставлять в финальных стратегиях (стратегиях по умолчанию), закрывающих цепочку по
группе параметров фильтра. Таких мест может быть несколько.
Не нужно использовать в узких специализациях и в тех профилях, по которым точно не будет проходить
трафик с известными протоколами, откуда поддерживается извлечение имени хоста (`http`, `tls`, `quic`).
- это вариация, при которой стандартный автолист используется как обычный.
То есть на этом профиле не происходит автоматическое добавление заблокированных доменов.
Но если на другом профиле что-то будет добавлено, то этот профиль примет изменения автоматически.
***Изменение бита mark для предотвращения зацикливания***\
`DESYNC_MARK=0x40000000`
***Изменение бита mark для пометки пакетов, проходящих по POSTNAT схеме (только nftables)***\
`DESYNC_MARK_POSTNAT=0x20000000`
***Если раскоментировано, пометка пакетов, которые должны быть обработаны zapret.***\
`#FILTER_MARK=0x10000000`
Бит должен быть установлен вашими собственными правилами.
* Для iptables - в цепочках mangle PREROUTING и mangle OUTPUT перед правилами zapret (iptables -I _после_ применения правил zapret).
* Для nftables - в хуках output и prerouting с приоритетом -102 или ниже.
Критерии пометки любые. Например, IP адрес или интерфейс источника. Это ответ на вопрос "как мне сделать, чтобы телик не ходил через zapret или чтобы через него ходил только мой комп".
***Включение стандартной опции tpws в режиме socks***\
`TPWS_SOCKS_ENABLE=0`
***На каком порту будет слушать tpws socks. прослушивается только localhost и LAN***\
`TPPORT_SOCKS=987`
***Параметры tpws для режима socks***
```
TPWS_SOCKS_OPT="
--filter-tcp=80 --methodeol --new
--filter-tcp=443 --split-pos=1,midsld --disorder "
```
***Включение стандартной опции tpws в прозрачном режиме***\
`TPWS_ENABLE=0`
***Какие tcp порты следует перенаправлять на tpws***\
`TPWS_PORTS=80,443`
***Параметры tpws для прозрачного режима***
```
TPWS_OPT="
--filter-tcp=80 --methodeol --new
--filter-tcp=443 --split-pos=1,midsld --disorder "
```
***Включение стандартной опции nfqws***\
`NFQWS_ENABLE=0`
***Какие tcp и udp порты следует перенаправлять на nfqws с использованием connbytes ограничителя***
connbytes позволяет из каждого соединения перенаправить только заданное количество начальных пакетов по каждому направлению - на вход и на выход.
Это более эффективная kernel-mode замена параметра nfqws `--dpi-desync-cutoff=nX`.
```
NFQWS_PORTS_TCP=80,443
NFQWS_PORTS_UDP=443
```
***Сколько начальных входящих и исходящих пакетов нужно перенаправлять на nfqws по каждому направлению***
```
NFQWS_TCP_PKT_OUT=$((6+$AUTOHOSTLIST_RETRANS_THRESHOLD))
NFQWS_TCP_PKT_IN=3
NFQWS_UDP_PKT_OUT=$((6+$AUTOHOSTLIST_RETRANS_THRESHOLD))
NFQWS_UDP_PKT_IN=0
```
***Задать порты для перенаправления на nfqws без connbytes ограничителя***\
Есть трафик, исходящий сеанс для которого необходимо перенаправлять весь без ограничителей.
Типичное применение - поддержка http keepalives на stateless DPI.
Это существенно нагружает процессор. Использовать только если понимаете зачем. Чаще всего это не нужно.
Входящий трафик ограничивается по connbytes через параметры PKT_IN.
Если указываете здесь какие-то порты, желательно их убрать из версии с connbytes ограничителем
```
NFQWS_PORTS_TCP_KEEPALIVE=80
NFQWS_PORTS_UDP_KEEPALIVE=
```
***Параметры nfqws***
```
NFQWS_OPT="
--filter-tcp=80 --dpi-desync=fake,multisplit --dpi-desync-split-pos=method+2 --dpi-desync-fooling=md5sig --new
--filter-tcp=443 --dpi-desync=fake,multidisorder --dpi-desync-split-pos=1,midsld --dpi-desync-fooling=badseq,md5sig --new
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=6
```
***Режим фильтрации хостов:***
```
none - применять дурение ко всем хостам
ipset - ограничить дурение ipset-ом zapret/zapret6
hostlist - ограничить дурение списком хостов из файла
autohostlist - режим hostlist + распознавание блокировок и ведение автоматического листа
```
`MODE_FILTER=none`
***Настройка системы управления выборочным traffic offload (только если поддерживается)***
```
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"
```
Хук, позволяющий внести ip адреса динамически. $1 = имя таблицы\
Адреса выводятся в stdout. В случае nfset автоматически решается проблема возможного пересечения интервалов.\
`IPSET_HOOK="/etc/zapret.ipset.hook"`
***ПРО РУГАНЬ в 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"
```
***Настройка режима autohostlist.***
При увеличении AUTOHOSTLIST_RETRANS_THRESHOLD и использовании nfqws следует пересмотреть значения параметров
NFQWS_TCP_PKT_OUT и NFQWS_UDP_PKT_OUT. Все ретрансмиссии должны быть получены nfqws, иначе триггер "зависание запроса" не сработает.
```
AUTOHOSTLIST_RETRANS_THRESHOLD=3
AUTOHOSTLIST_FAIL_THRESHOLD=3
AUTOHOSTLIST_FAIL_TIME=60
AUTOHOSTLIST_DEBUG=0
```
***Включить или выключить сжатие больших листов в скриптах 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"`
В OpenWrt в качестве wan берутся интерфейсы, имеющие default route. Отдельно для ipv4 и ipv6.
Это можно переопределить:
```
OPENWRT_WAN4="wan4 vpn"
OPENWRT_WAN6="wan6 vpn6"
```
Параметр `INIT_APPLY_FW=1` разрешает init скрипту самостоятельно применять правила iptables.\
При иных значениях или если параметр закомментирован, правила применены не будут.\
Это полезно, если у вас есть система управления фаерволом, в настройки которой и следует прикрутить правила.\
На OpenWrt неприменимо при использовании firewall3+iptables.
`FILTER_TTL_EXPIRED_ICMP=1` включает механизмы блокировки пакетов icmp time exceeded, высылаемые роутерами по пути следования пакета в ответ на исчерпание TTL/HL.
В linux соединение обрывается системой, если в ответ на первый пакет (для tcp - SYN) пришел такой icmp. Аналогичная схема имеется и в datagram сокетах.
Блокировка icmp идет исключительно за счет средств iptables/nftables.
Чтобы не трогать весь трафик, в режиме PRENAT используется connmark для пометки сеансов, над которыми поработал nfqws. В режиме POSTNAT так сделать нельзя,
поэтому помечаются все сеансы, заворачиваемые на nfqws.
Настройку лучше отключить, если вы не ожидаете проблем от icmp, тк в этом случае будет меньше ненужных вмешательств в трафик.
***Следующие настройки не актуальны для openwrt:***
Если ваша система работает как роутер, то нужно вписать названия внутренних и внешних интерфейсов:
```
IFACE_LAN=eth0
IFACE_WAN=eth1
IFACE_WAN6="henet ipsec0"
```
Несколько интерфейсов могут быть вписаны через пробел.
Если IFACE_WAN6 не задан, то берется значение IFACE_WAN.
`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.
Может быть полезно, если вам нужно использовать nftables set-ы, например `ipban`/`ipban6`.
nfset-ы принадлежат только одной таблице, следовательно вам придется писать правила для таблицы zapret,
а значит нужно синхронизироваться с применением/снятием правил со стороны zapret скриптов.
## custom 方案
custom скрипты - это маленькие shell программы, управляющие нестандартными режимами применения zapret
или частными случаями, которые не могут быть интегрированы в основную часть без загромождения и замусоривания кода.
Для применения custom следует помещать файлы в следующие директории в зависимости от вашей системы:
```
/opt/zapret/init.d/sysv/custom.d
/opt/zapret/init.d/openwrt/custom.d
/opt/zapret/init.d/macos/custom.d
```
Директория будет просканирована в алфавитном порядке, и каждый скрипт будет применен.
В `init.d` имеется `custom.d.examples.linux`, в `init.d/macos` - `custom.d.examples`.
Это готовые скрипты, которые можно копировать в `custom.d`. Их можно взять за основу для написания собственных.
***Для linux пишется код в функции***
```
zapret_custom_daemons
zapret_custom_firewall
zapret_custom_firewall_nft
zapret_custom_firewall_nft_flush
```
***Для macos***
```
zapret_custom_daemons
zapret_custom_firewall_v4
zapret_custom_firewall_v6
```
zapret_custom_daemons поднимает демоны **nfqws**/**tpws** в нужном вам количестве и с нужными вам параметрами.
В первом параметре передается код операции: 1 = запуск, 0 = останов.
Схема запуска демонов в OpenWrt отличается - используется procd.
Поэтому логика останова отсутствует за ненадобностью, останов никогда не вызывается.
zapret_custom_firewall поднимает и убирает правила `iptables`.
В первом параметре передается код операции: 1 = запуск, 0 = останов.
zapret_custom_firewall_nft поднимает правила nftables.
Логика останова отсутствует за ненадобностью. Стандартные цепочки zapret удаляются автоматически.
Однако, sets и правила из ваших собственных цепочек не удаляются.
Их нужно подчистить в zapret_custom_firewall_nft_flush.
Если set-ов и собственных цепочек у вас нет, функцию можно не определять или оставить пустой.
Если вам не нужны iptables или nftables - можете не писать соответствующую функцию.
В linux можно использовать локальные переменные `FW_EXTRA_PRE` и `FW_EXTRA_POST`.\
`FW_EXTRA_PRE` добавляет код к правилам ip/nf tables до кода, генерируемого функциями-хелперами.\
`FW_EXTRA_POST` добавляет код после.
В linux функции-хелперы добавляют правило в начало цепочек, то есть перед уже имеющимися.
Поэтому специализации должны идти после более общих вариантов.
Для macos правило обратное. Там правила добавляются в конец.
По этой же причине фаервол в Linux сначала применяется в стандартном режиме, потом custom,
а в MacOS сначала custom, потом стандартный режим.
В macos firewall-функции ничего сами никуда не заносят. Их задача - лишь выдать текст в stdout,
содержащий правила для pf-якоря. Остальное сделает обертка.
Особо обратите внимание на номер демона в функциях `run_daemon` , `do_daemon`, `do_tpws`, `do_tpws_socks`, `do_nfqws` ,
номера портов **tpws** и очередей **nfqueue**.
Они должны быть уникальными во всех скриптах. При накладке будет ошибка.
Поэтому используйте функции динамического получения этих значений из пула.
`custom` скрипты могут использовать переменные из `config`. Можно помещать в `config` свои переменные
и задействовать их в скриптах.
Можно использовать функции-хелперы. Они являются частью общего пространства функций shell.
Полезные функции можно взять из примеров скриптов. Так же смотрите `common/*.sh`.
Используя хелпер функции, вы избавитесь от необходимости учитывать все возможные случаи
типа наличия/отсутствия ipv6, является ли система роутером, имена интерфейсов, ...Хелперы это учитывают. Вам нужно сосредоточиться лишь на фильтрах `{ip,nf}tables` и параметрах демонов.
## 简单安装
`install_easy.sh` автоматизирует ручные варианты процедур установки.
Он поддерживает OpenWrt, linux системы на базе systemd или openrc и MacOS.
Для более гибкой настройки перед запуском инсталлятора следует выполнить раздел "Выбор параметров".
如果支持系统启动,但使用了安装程序不支持的包管理器,或者包名与安装程序中指定的不一致,则需要手动安装包。
始终需要 curl。`ipset` 仅用于 `iptables` 模式,`nftables` 不需要。
对于非常精简的发行版(如 alpine),需要单独安装 `iptables` 和 `ip6tables`,或者 `nftables`。
套件中包含适用于大多数架构的静态二进制文件。其中某一个有 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` 执行。卸载完成后,可以删除目录 `/opt/zapret`。
## systemd 下的安装
如果您喜欢 systemd 并希望最大程度地适应它,可以放弃 zapret 启动脚本,并将 `tpws` 和 `nfqws` 实例作为单独的 systemd 单元启动。同时,您必须手动编写 iptables/nftables 规则并以某种方式加载它们。例如,为此编写一个额外的 systemd unit。
还需要通过 `make systemd` 以特殊方式编译二进制文件。
zapret 套件中包含模板 `init.d/systemd/{nfqws@.service,tpws@.service}`。
使用它们的简要命令列表在这些文件的注释中给出。
## openwrt 简易安装
仅在路由器上有足够空间时有效。
将 zapret 复制到路由器的 `/tmp`。
运行安装程序:\
`sh /tmp/zapret/install_easy.sh`
它将仅把必要的最少文件复制到 `/opt/zapret`。
成功安装后,可以从 tmp 中删除 zapret 以释放 RAM:\
`rm -r /tmp/zapret`
为了更灵活的配置,应在运行安装程序之前执行“选择参数”部分。
简易安装系统旨在处理对文件权限的任何故意或意外更改。
对在 windows 下重新打包具有抵抗力。复制到 `/opt` 后,权限将被强制恢复。
## 磁盘空间严重不足模式下的 openwrt 安装
磁盘上需要大约 120-200 kb 的空间。必须放弃除 **tpws** 以外的所有组件。
**适用于 nftables 的 openwrt 22 及更高版本的说明**
无需安装任何依赖项。
***安装:***
1. 将 `init.d/openwrt-minimal/tpws/*` 中的所有内容复制到 openwrt 根目录。
2. 将适合该架构的 **tpws** 二进制文件复制到 `/usr/bin/tpws`。
3. 设置文件权限:`chmod 755 /etc/init.d/tpws /usr/bin/tpws`
4. 编辑 `/etc/config/tpws`
* 如果不需要 ipv6,请编辑 `/etc/nftables.d/90-tpws.nft` 并注释掉带有 ipv6 重定向的行。
5. `/etc/init.d/tpws enable`
6. `/etc/init.d/tpws start`
7. `fw4 restart`
***完全删除:***
1. `/etc/init.d/tpws disable`
2. `/etc/init.d/tpws stop`
3. `rm -f /etc/nftables.d/90-tpws.nft /etc/firewall.user /etc/init.d/tpws /usr/bin/tpws`
4. `fw4 restart`
**适用于 iptables 的 openwrt 21 及更低版本的说明**
***安装依赖项:***
1. `opkg update`
2. `opkg install iptables-mod-extra`
* 仅用于 IPV6:`opkg install ip6tables-mod-nat`
确保 `/etc/firewall.user` 中没有任何重要内容。
如果有,请不要盲目遵循说明。合并代码或在 `/etc/config/firewall` 中创建您自己的 `firewall include`。
***安装:***
1. 将 `init.d/openwrt-minimal/tpws/*` 中的所有内容复制到 openwrt 根目录。
2. 将适合该架构的 **tpws** 二进制文件复制到 `/usr/bin/tpws`。
3. 设置文件权限:`chmod 755 /etc/init.d/tpws /usr/bin/tpws`
4. 编辑 `/etc/config/tpws`
* 如果不需要 ipv6,请编辑 /etc/firewall.user 并在那里设置 DISABLE_IPV6=1。
5. `/etc/init.d/tpws enable`
6. `/etc/init.d/tpws start`
7. `fw3 restart`
***完全删除:***
1. `/etc/init.d/tpws disable`
2. `/etc/init.d/tpws stop`
3. `rm -f /etc/nftables.d/90-tpws.nft /etc/firewall.user /etc/init.d/tpws`
4. `touch /etc/firewall.user`
5. `fw3 restart`
## Android
没有 root 权限,请忘记 nfqws 和透明代理模式下的 tpws。tpws 只能在 `--socks` 模式下工作。
Android 内核支持 NFQUEUE。nfqws 可以工作。
stock 内核不支持 ipset。通常情况下,在 Android 上启用 ipset 的任务复杂程度从“不简单”到“几乎不可能”不等。除非您能为您的设备找到现成的编译好的内核。
tpws 在任何情况下都能工作,它不需要任何特别的东西。
虽然 Android 下的 Linux 变体可以工作,但建议使用专门为 bionic 编译的二进制文件。
它们不会有 DNS、本地时间以及用户和组名的问题。\
建议使用 gid 3003 (AID_INET)。否则,您可能会在创建套接字时遇到 permission denied。
例如:`--uid 1:3003`\
在 iptables 中指定:`! --uid-owner 1` 而不是 `! --uid-owner tpws`。\
编写一个带有 iptables 和 tpws 的 shell 脚本,并使用您的 root 管理器启动它。
自动启动脚本位于此处:\
magisk : /data/adb/service.d\
supersu: /system/su.d
**nfqws** 可能存在这样的故障。当以默认 uid (0x7FFFFFFF) 启动,且在蜂窝接口上工作并断开外部电源线时,系统可能会部分冻结。触摸和按钮停止工作,但屏幕上的动画可能仍在继续。如果屏幕已熄灭,则无法通过电源按钮将其打开。
将 UID 更改为较低的值(--uid 1 即可)可以解决此问题。
该故障是在基于 mediatek 平台的设备上的 android 8.1 上发现的。
回答在没有 root 的 android 上将 tpws 放在哪里以便随后从应用程序启动的问题。
通过 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
```
如何找到蜂窝运营商的绕过策略:最简单的方法是共享网络给电脑。
任何受支持的操作系统都可以。通过 USB 电缆将 android 连接到电脑并开启调制解调器模式。
运行标准的 blockcheck 过程。将规则移植到手机时,如果策略中存在 TTL 规则,请将 TTL 减少 1。如果在 windows 上检查,请删除参数 `--wf-*`。
不支持在 android shell 中运行 blockcheck,但如果有 root,您可以部署某个 linux 发行版的 rootfs。
最好通过 adb shell 从电脑上执行此操作。
如果没有电脑,则部署 chroot 是唯一的选择,尽管不太方便。
一些轻量级的东西都行,例如 alpine 甚至 OpenWrt。
如果这不是 android 模拟器,那么通用架构是 arm(任何变体)。
如果您确定您的操作系统是 64 位的,那么最好使用 arm64 而不是 arm。
可以通过命令 `uname -a` 找出架构。
```
mount --bind /dev /data/linux/dev
mount --bind /proc /data/linux/proc
mount --bind /sys /data/linux/sys
chroot /data/linux
```
您首先需要配置一次 DNS。它不会自动启动。
`echo nameserver 1.1.1.1 >/etc/resolv.conf`
接下来,您需要使用包管理器安装 iptables-legacy。务必是 **非** iptables-nft,它通常是默认存在的。Android 内核中没有 nftables。\
`ls -la $(which iptables)`\
链接应指向 legacy 版本。
如果不是,请安装发行版所需的软件包,并确保链接正确。\
`iptables -S`\
这样您可以检查您的 `iptables` 是否看到了 Android 塞进去的内容。`iptables-nft` 会报错。
接下来将 zapret 下载到 `/opt/zapret`。使用 `install_prereq.sh`、`install_bin.sh`、`blockcheck.sh` 进行常规操作。
请注意,蜂窝运营商和家庭 Wi-Fi 的绕过策略可能会有所不同。
可以通过 iptables 参数 `-o ` 轻松区分蜂窝运营商。名称可能是例如 `ccmni0`。
通过 `ifconfig` 很容易看到。
Wi-Fi 网络通常是 `wlan0`。
可以通过开启或关闭 Wi-Fi,将 blockcheck 在运营商和 Wi-Fi 之间切换(连同整个互联网)。
如果您找到了 Wi-Fi 的策略并将其写入自动启动,那么当连接到另一个 Wi-Fi 时,它可能不起作用或完全损坏某些东西,因此请考虑是否值得。
最好制作诸如“启动家庭 Wi-Fi 绕过”、“停止家庭 Wi-Fi 绕过”之类的脚本,并在需要时从终端使用它们。
但家庭 Wi-Fi 最好还是在路由器上绕过。
## 华为移动调制解调器和路由器
E3372、E8372、E5770 等设备共享共同的系统构建理念。
有 2 个计算核心。一个核心运行 vxworks,另一个运行 linux。
4pda 上有带有 telnet 和 adb 的修改版固件。应该使用这些。
以下声明已在 E8372 上验证。其他的可能类似或相近。
存在用于网络功能 offload 的额外硬件块。
并非所有流量都通过 linux。来自调制解调器本身的传出流量正常通过 OUTPUT 链,在 FORWARD =>wan 上,部分数据包从 tcpdump 中丢失。
tpws 以常规方式工作。
`nfqueue` 已损坏,您可以使用来自 huawei open source 的源代码构建修复模块 https://github.com/im-0/unfuck-nfqueue-on-e3372h。源代码包含工具链和一个半编译的、过时的内核。配置可以从 `/proc/config.gz` 中的工作调制解调器获取。
使用这些源代码,熟练的人可以编译 `unfuck_nfqueue.ko` 模块。
应用后,NFQUEUE 和适用于 arm 的 nfqws 可以正常工作。
为避免在使用 nfqws 时出现 offload 问题,应结合 tcp proxy 模式下的 tpws 和 nfqws。
NFQUEUE 规则针对 OUTPUT 链编写。
connbytes 不得不放弃,因为内核中没有该模块。但这并不致命。
自动启动脚本为 `/system/etc/autorun.sh`。创建您自己的 zapret 配置脚本,并通过“&”从 autorun.sh 末尾启动。脚本应在开始时执行 sleep 5,以等待网络和华为的 iptables 启动。
```
curl www.ru
curl: (7) Failed to connect to www.ru port 80: Host is unreachable
```
出现套接字错误 EHOSTUNREACH (errno -113)。在 tpws 中也可以看到同样的情况。
浏览器中网页的一部分、图片、样式无法加载。
在外部接口 eth_x 的 tcpdump 中,只能看到单个无响应的 SYN 包,没有 ICMP 消息。
操作系统以某种方式得知无法建立 TCP 连接并发出错误。
如果从客户端执行连接,则 SYN 丢失,连接无法建立。
客户端操作系统进行重传,并在某次连接成功。
因此,在没有 tcp 代理的情况下,网站在这种情况会变慢,但会加载;而在使用代理的情况下,连接会建立,但很快断开且没有任何数据,浏览器不会尝试重新建立连接。因此,使用 tpws 的浏览质量可能会更差,但这并不是 tpws 的问题。
如果运行 torrent 客户端且存在大量 tcp 连接,重置的频率会显着增加。
但是,原因不在于 conntrack 表溢出。增加限制和清理 conntrack 没有帮助。
据推测,此特性与硬件 offload 中的数据包重置处理有关。
我对这个问题没有确切的答案。如果您知道,请分享。
为避免降低浏览质量,可以按 ip 过滤对 tpws 的重定向。
不支持 ipset。因此,所有能做的就是为少量主机创建单独的规则。
[files/huawei](./../files/huawei/) 中提供了一些脚本草稿。_不是现成的解决方案!_ 请查看、研究并自行调整。\
此处可以下载适用于 arm 的现成有用的静态二进制文件,包括 curl:https://github.com/bol-van/bins
## FreeBSD, OpenBSD, MacOS
在 [BSD 文档](./bsd.md) 中有
## Windows
在 [Windows 文档](./windows.md) 中有说明
## 其他固件
对于静态二进制文件而言,它们在何处运行并不重要:PC、android、机顶盒、路由器、任何其他设备。
任何固件、Linux 发行版都适用。静态二进制文件可以在所有设备上运行。
它们只需要具有必要编译选项或模块的内核。
但是,除了二进制文件外,项目中还使用了脚本,其中使用了一些标准程序。
无法直接将此系统安装到任何设备上的主要原因:
* 缺乏通过 shell 访问设备的能力
* 缺乏 root 权限
* 缺乏用于写入和非易失性存储文件的 r/w 分区
* 缺乏将任何东西放入自动启动的能力
* 缺乏 cron
* netfilter 中不可禁用的 flow offload 或其他专有技术
* 内核模块或其编译选项不足
* iptables 模块不足 (/usr/lib/iptables/lib*.so)
* 缺乏标准程序(如 ipset、curl)或它们被阉割(简化版替代品)
* 阉割版或非标准的 sh shell
如果您的固件具备所有必要组件,您可以或多或少地将 zapret 适配到您的设备。
您可能无法启动系统的所有部分,但至少可以尝试启动 tpws 并通过 -j REDIRECT 将端口 80 上的所有流量重定向到它。
如果您有地方写入 tpws,并且能够在启动时执行命令,那么至少这是您可以做到的。内核很可能支持 REDIRECT。在任何路由器上肯定都有,在其他设备上则不确定。大多数固件上缺少 NFQUEUE、ipset,因为不需要。
重新编译内核或其模块很可能非常困难。
为此,您至少需要获取固件的源代码。
如果有地方写入,用户模式组件可以相对轻松地引入。
对于具有 r/w 区域的设备,专门存在 entware 项目。
某些固件甚至可以通过 Web 界面轻松安装它。
entware 包含一个用户模式组件存储库,安装在 /opt 中。
它们的帮助可以弥补主固件软件的不足,内核除外。
您可以尝试按照“附加到防火墙管理系统或您自己的启动系统”一节中所述的方式使用 sysv init 脚本。
如果抱怨缺少某些基本程序,则应通过 entware 补充。
在运行脚本之前,必须将附加程序的路径放入 PATH 中。
_其他固件的详细设置描述超出了本项目的范围。_
OpenWrt 是为数不多的相对完整的嵌入式设备 Linux 系统之一。
它具有以下特征,这些特征也是选择此固件的基础:
* 通过 shell 完全 root 访问设备。出厂固件通常缺少,许多替代固件则有
* r/w 根目录。这几乎是 OpenWrt 独有的功能。出厂和大多数替代固件基于 squashfs root (r/o) 构建,配置存储在称为 nvram 的特殊格式内置存储器区域中。没有 r/w 根目录的系统受到严重限制。它们无法在没有特殊技巧的情况下从存储库安装软件,主要面向比普通用户稍高级的用户,并通过 Web 界面管理现有功能,但功能受到固定限制。替代固件通常可以将 r/w 分区挂载到文件系统的某个区域,出厂固件通常只能挂载连接到 USB 的闪存驱动器,而且不一定支持 unix 文件系统。可能仅支持 fat 和 ntfs。
* 将根文件系统移动到外部存储器或在其上创建覆盖层的可能性
* 存在包管理器 opkg 和软件存储库
* flow offload 可预测、标准且可选地受控,并且可禁用
* 存储库中拥有所有内核模块,可以通过 opkg 安装。无需重新编译内核。
* 存储库中拥有所有 iptables 模块,可以通过 opkg 安装
* 存储库中拥有大量标准程序和附加软件
* 存在 SDK,允许编译缺失的组件
## 通过第三方主机绕过封锁
如果自主绕过不起作用,则必须通过第三方主机重定向流量。
建议通过 `iptables+redsocks` 或 `iptables+iproute+vpn` 使用通过 socks5 的透明重定向。
OpenWrt 上 redsocks 变体的配置在 [redsocks.txt](./redsocks.txt) 中有说明。
`iproute+wireguard` 变体的配置在 [wireguard_iproute_openwrt.txt](./wireguard_iproute_openwrt.txt) 中。
## 为什么值得投资购买 VPS
VPS 是虚拟专用服务器。有许多数据中心提供此服务。
VPS 可以执行任何任务。从简单的网站到复杂的自研系统。
VPS 也可以用于搭建自己的 VPN 或代理。
可能的应用方式非常广泛,且服务普及率高,最大限度地减少了监管机构封锁此类服务的能力。是的,如果引入白名单,该解决方案将失效,但这将是另一种现实,届时将需要发明其他解决方案。
在此之前,没有人会因为提供托管服务而封锁托管商。
作为一个体,你可能根本不被关注。想想你与知名 VPN 提供商的区别。
VPN 提供商为大众提供简单且易于访问的绕过封锁服务。
这一事实使其成为封锁的首要目标。RKN 会发出通知,拒绝合作后将封锁 VPN。预付费用将打水漂。
监管机构没有也永远不会拥有资源来全面检查网络中的每个服务器。
可能出现中国式的情况,即 DPI 识别 VPN 协议并动态封锁提供非许可 VPN 的服务器 IP。但拥有知识和头脑,您始终可以混淆 VPN 流量或应用其他更耐受 DPI 分析的 VPN 类型,或者仅仅是不太广为人知因此被监管机构发现的可能性较小的类型。
您可以自由地在您的 VPS 上做任何您想做的事,以适应新条件。
是的,这需要知识。您可以选择学习并控制局势,当没有什么能被禁止时,或者屈服于系统。
VPS 可以在很多地方购买。有专门搜索 VPS 优惠的门户网站。\
例如,[这个](https://vps.today)。
对于个人 VPN 服务器,通常最低配置就足够了,但需要无限流量或大流量限制(TB 级)。VPS 的类型也很重要。OpenVZ 适用于 OpenVPN,但您无法在其上运行 WireGuard、IPsec,即所有需要 kernel mode 的东西。
对于 kernel mode,
修复脚本
``` append_separator_list() { # $1 - var name to receive result # $2 - separator # $3 - quoter # $4,$5,... - elements local _var="$1" sep="$2" quo="$3" i eval i="\$$_var" shift; shift; shift while [ -n "$1" ]; do if [ -n "$i" ] ; then i="$i$sep$quo$1$quo" else i="$quo$1$quo" fi shift done eval $_var="\$i" } resolve_lower_devices() { # $1 - bridge interface name [ -d "/sys/class/net/$1" ] && { find "/sys/class/net/$1" -follow -maxdepth 1 -name "lower_*" | { local l lower lowers while read lower; do lower="$(basename "$lower")" l="${lower#lower_*}" [ "$l" != "$lower" ] && append_separator_list lowers ' ' '' "$l" done printf "$lowers" } } } # 它会破坏 nfqueue lans=$(resolve_lower_devices br-lan) for int in $lans; do ethtool -K $int rx-gro-list off done ```标签:DNS枚举, DPI绕过, GFW, TCP分段, 中间人攻击, 代码注入, 俄罗斯, 匿名访问, 协议分析, 反审查, 客户端加密, 序列号重叠, 开源, 数据包构造, 数据包欺骗, 数据包注入, 权限提升, 欺骗技术, 流量伪装, 深度包检测, 破网软件, 网络安全分析, 网络安全工具, 网络审查, 网络流量分析, 网络隐私, 翻墙, 配置错误, 防御绕过, 防火墙