Zapret: what's new

Исправлен существенный косяк blockcheck.
На curl, собранном с использованием версии openssl с quic (quictls), библиотека не определялась как openssl и не включался параметр tls-max.
Поэтому все запросы шли реально на tls1.3, что давало искаженную картину.

Добавлен специфический seqovl тест на подсовывание полного ClientHello от iana.org. Аналог fake,split2 , только в одном флаконе.
ТСПУ отстает от такого TLS 1.2 запроса, не проверяя ответ сервера, и поэтому не нужен --wssize , снижающий скорость

- checking nfqws --dpi-desync=split2 --dpi-desync-split-seqovl=1 --dpi-desync-split-pos=2
curl: (35) Recv failure: Connection reset by peer
UNAVAILABLE code=35
- checking nfqws --dpi-desync=split2 --dpi-desync-split-seqovl=336 --dpi-desync-split-seqovl-pattern=/opt/zapret/files/fake/tls_clienthello_iana_org.bin
!!!!! AVAILABLE !!!!!

336 потому, что остаток до 517 байт заполнен нулями. ТСПУ их игнорирует. У нас же пойдет начало реального запроса вместо нулей. По умолчанию 2 байта.

В zapret-win-bundle еще косяк. Не положил files/fake. Из-за этого все тесты, их использующие, не работали.
/bin/sh был копией /bin/bash. Заменено на dash. dash в несколько раз быстрее bash. blockcheck стал бегать повеселее

В winws в добавок к ssid-filter сделан NLM filter.

--nlm-filter=net1[,net2,net3,...] ; включать winws только когда подключена любая из указанных сетей NLM
--nlm-list[=all] ; вывести список сетей NLM. по умолчанию только подключенных, all - всех.

–nlm-filter аналогичен --ssid-filter, но работает с именами или GUIDами сетей Network List Manager (NLM). Это те сети, которые вы видите в панели управления в разделе “Центр управления сетями и общим доступом”. Под сетью подразумевается не конкретный адаптер, а именно сетевое окружение конкретного подключения. Обычно проверяется mac адрес шлюза. К сети можно подключиться через любой адаптер, и она останется той же самой. Если подключиться, допустим, к разными роутерам по кабелю, то будут разные сети. А если к одному роутеру через 2 разных сетевых карточки на том же компе - будет одна сеть. NLM абстрагирует типы сетевых адаптеров. Он работает как с wifi, так и с ethernet и любыми другими. Поэтому это более универсальный метод, чем ssid фильтр.

В режим autohostlist внесен дополнительный механизм избегания ложных срабатываний.
Раньше чтобы добавить в лист домен нужно было, чтобы он фейлился столько-то раз на протяжении такого-то времени. При этом могло быть так. Плохо, хорошо, плохо, хорошо, хорошо, плохо. Это вызывало попадание в лист. Сейчас “хорошо” сразу же сбрасывает счетчик “плохо”. Цель - обнаружить постоянное “плохо”. Если оно через раз, значит либо это проблемы самого сайта (перегруз, например), либо ваша стратегия обхода неустойчива.
Работает и в nfqws, и в tpws.
Под “хорошо” понимается прием любых данных от сервера, не содержащих http redirect на другой домен (заглушку), либо отсыл любого пакета с sequence number, выходящим за пределы TLS ClientHello (то есть процесс пошел дальше, значит клиент принял что-то от сервера, и это уже не затык на DPI)

В blockcheck сделана корректная зачистка при обрыве терминала. Например, отвалился ssh.

Из git удалены все изменяемые файлы. Это config, init.d/{macos,sysv,openwrt}/custom, ipset/zapret-hosts-user*.txt
Они переименованы с расширением .default.
Инсталятор если увидит отсутствие этих файлов скопирует их с .default
blockcheck скопирует только config
zapret-hosts-user-ipban.txt и zapret-hosts-user.txt удалены. они заполняются кодом в инсталяторе.

Это сделано чтобы можно было не парясь накатывать файлы поверх имеющейся инсталяхи или делать git pull не парясь о нестыковках.

Распространенная проблема, связанная с ютубе,

Чел сканирует блокчеком, находит стратегию с TTL. Она обходит большинство заблокированных ресурсов.
Чел добавляет googlevideo.com. Он ломается.
Догадайтесь почему. <вступает в силу необходимость понимать что пишешь, а не копировать>

Спойлер

Все дело в том, что GGC ставятся поближе к провайдеру и часто имеют длину пути ниже указанного в стратегии. Фейки доходят до сервера и ломают сеанс.
Решение - добавить ограничитель. Наиболее совместимый - --dpi-desync-fooling=md5sig
Если у вас работает --dpi-desync-fooling=datanoack, то можно избавиться от TTL полностью.
Он вероятно не будет работать через домашний роутер, но может работать с него.

другая возможная причина тупняка - не настроен обход quic
да, quic они тоже замедляют. работает --dpi-desync=fake.
его нельзя сочетать с ttl.
возможно, какие-то ТСПУ еще не научились разбирать kyber quic, потому на них дефолтный хроме может обходить замедление сам по себе. потому в сети ходит противоречивая инфа то включать quic, то выключать. GDPI quic не поддерживает.
так же известно, что у ТСПУ исторически были проблемы с пакетами quic от разных библиотек разных версий. и на протяжении истории это менялось. они что-то доделывали.
с zapret-ом , наверно, лучше все-же сделать fake на quic. хуже не станет. и kyber тоже поддерживается

Еще немного наблюдений по поводу обхода замедления ютубе.

split2 работает, но исключительно потому, что позиция по умолчанию - 2.
Работает простой сплит на позиции 1 и 2. 3 байта в начале - это маркер TLS. Если DPI видит TLS оно начинает реассемблировать пакеты до получения full tls client hello. Внедрение кибера не оставила вариантов цензорам. Приходится реассемблить.
Поэтому простые сплиты на позиции более 2 не срабатывают.
Но работает практически любая мишура. fake, disorder2, oob, split.

Написал краткий FAQ по поводу обхода youtube средствами zapret :

Оказывается, не так все просто с windows 7 и готовым winws из комплекта zapret.

Требования к подписи драйверов windows изменились в 2021 году. Официальные бесплатные обновления windows 7 закончились в 2020. После этого несколько лет продолжали идти платные обновления по программе ESU. Именно в этих ESU обновлениях находится обновление ядра windows 7, позволяющиее загрузить драйвер windivert 2.2.2-A, который идет в поставке zapret.
Поэтому варианты следующие :

  1. Взять windivert64.sys и windivert.dll версии 2.2.0-C или 2.2.0-D отсюда : Index of /download/
    и заменить эти 2 файла. В zapret-win-bundle есть отдельных 2 места, где находится winws : zapret-winws и blockcheck/zapret/nfq. Надо менять в обоих местах. Этот вариант проверен и должен работать. Тем не менее патч 10 летней давности, который включает SHA256 сигнатуры, все еще необходим.

  2. Взломать ESU : Windows 7 ESU Patching · HackAndPwn
    Скрипт для установки и интеграции платных обновлений (ESU)
    и обновить систему

  3. Использовать UpdatePack7R2 от simplix : https://blog.simplix.info
    Но с этим паком есть проблема. Автор из Украины, он очень обиделся на русских. Если в панели управления стоит регион RU или BY, появляется неприятный диалог. Чтобы эту проблему обойти, можно поставить временно любой другой регион, потом вернуть. Так же нет никаких гарантий, что автор не насовал туда какой-то зловредный код. Использовать на свой страх и риск.
    Более безопасный вариант - скачать последнюю нормальную версию : 22.2.10
    Набор обновлений UpdatePack7R2 для Windows 7 SP1 и Server 2008 R2 SP1 22.2.10 [Multi/Ru] :: NNM-Club
    Ее достаточно, чтобы windivert 2.2.2-A заработал на windows 7.

Оказалось, что утечки памяти ядра и падения кинетика при использовании nfqws к zapret отношения не имеют. Кинетик использует старое ядро с багом, который давно пофиксили, но в кинетике непатченная версия. Разрабы собираются выкатывать патч в новых прошивках

Очередное обновление.

Почистили немного C код по результатам статического и динамического анализа

В dvtws больше не используются raw сокеты для отсылки ipv4 пакетов. Вместо них используется divert. Поэтому “not sockarg” в правилах ipfw больше не нужно. Так же это призвано наладить совместимость с древними версиями BSD, где sockarg еще нет ( я не проверял, но кто-то писал issue, у него были проблемы из-за этого в freebsd 7.4, вышедшей в 2011 году ).
Но главной целью этого изменения было попробовать завести divert через divert-to в pf. Увы, попытка провалилась, идет зацикливание. Механизм предотвращения зацикливания divert в pf сломан в FreeBSD и как следствие в pf/opn sense включая версию ядра 14-RELEASE.
Кто-то выкатывал патч для ядра BSD, но видимо его еще не накатили в релизе.
А ipfw иногда глючит с pf вместе. Потому запуск dvtws на pf/opn sense может иметь неожиданные последствия.

В nfqws и tpws исправлен детект TLS ClientHello на очень старых криптолибах, которые шлют SSL 3.0 версию в TLS record layer , а в handshake - TLS 1.2. Старые телики самсунг, например.

nfqws и tpws теперь умеют логить --debug в файл и syslog.
syslog очень удобен на openwrt, потому что там используется logd с циклическим буфером в памяти. Читать через logread.
–debug параметр можно вносить в опции NFQWS или TPWS в конфиге, но лучше в самом начале, иначе не поймаются ошибки при анализе командной строки.

В tpws добавлена опция --connect-bind-addr. В ней можно задать ipv4 или ipv6 адрес, с которого будут выполняться исходящие подключения. Для указания и v4, и v6 можно опцию повторить.
Поддерживается и нотация fe80:xxxx:xxxx:…%interface_name для v6 link locals.
Однако , это не отменяет правил маршрутизации. Пакет пойдет на тот интерфейс, куда его направит система маршрутизации ip rule/ip route и прочее. Исключение - разве что link local. Там пойдет на тот интерфейс, который будет после %. По другому и нельзя применять link locals.
Так что не ждите чуда, чтобы направить коннект на какой-то специфический интерфейс.
На openwrt используются правила маршрутизации ipv6 с from, поэтому там это может сработать.
И не стоит удивляться, если вдруг вы указали адрес VPN, а в tcpdump оно идет на обычный инет с адресом обычного инета. Если default route на обычный инет более приоритетен, то ваш IP адрес VPN превращается через MASQUERADE в адрес обычного инета.
Вообщем, эта опция не есть панацея для выбора исходящего интерфейса сама по себе.

В tpws в режиме --debug добавлено логирование с какого enpoint-а (ip:source_port) идет подключение к удаленному ресурсу. Это может быть полезно для соотнесения лога tpws с дампом wireshark или tcpdump.

Немного переписана логика закрытия соединений в tpws.

Обнаружена такая проблема, что если клиент инициирует shutdown соединения, и нет неотосланных данных, tpws сразу же бросает оба конекта, не давая серверу дослать оставшиеся данные. Получается, клиент ждет последнего ответа, а ему приходит FIN, как будто сервер ничего не прислал.
Логика этой ситуации переписана с использованием вызова shutdown().
Теперь соединение через tpws должно корректно перекачивать все байтики до конца.
Так же сделан детект обрыва соединения через RST и воспроизведение RST на другом конце (leg).
Это секут броузеры. Если им приходит RST, они пытаются что-то делать еще, а если FIN, то могут посчитать, что сервер прислал пустышку (ошибка протокола).

В результате этих изменений могут появляться надолго подвисшие конекты через tpws, если один из концов принял соединение и повис, не отвечая на FIN.
Эта ситуация разрешается через FIN_WAIT timeout. Через какое-то время (до нескольких минут на BSD) соединения закроются.

Для смягчения вышеописанного недостатка с FIN_TIMEOUT на linux и macos сделал поддержку tcp user timeout. FreeBSD и OpenBSD не поддерживают.

–local-tcp-user-timeout и --remote-tcp-user-timeout устанавливают значение таймаута в секундах
для соединений клиент-прокси и прокси-сервер. Этот таймаут соответствует опции сокета linux
TCP_USER_TIMEOUT. Под таймаутом подразумевается время, в течение которого буферизированные данные не переданы или на переданные данные не получено подтверждение (ACK) от другой стороны.
Этот таймаут никак не касается времени отсутствия какой-либо передачи через сокет лишь потому,
что данных для передачи нет. Полезно для сокращения время закрытия подвисших соединений.
Поддерживается только на Linux и MacOS.

По умолчанию - 10 сек для local leg, 20 сек - для remote leg.
Если сделать 0, то setsockopt не будет выполнен, оставляя системное значение.

Проверил на эмуляторе android youtube app от google.
Тупит, не загружается.
Тупит на youtubei.googleapis.com и *.googlevideo.com
Остальное превьюшки - и еще что-то.
yt3.ggpht.com у меня вообще был заблокирован - зависание или RST

googlevideo.com
youtubei.googleapis.com
i.ytimg.com
yt3.ggpht.com

После задуривания всех этих доменов в режиме как на обход блокировок приложение работает нормально.

Провы по глупости стали дурить DPI, чтобы создать сиюминутное конкурентное преимущество.
В ответ в РКН включили особый режим против дурения на некоторых ggc.
Перестали работать фейки. Но им пришлось оставить разрешенными SNI от гуглодоменов.
Поэтому дописываем в стратегию --dpi-desync-fake-tls=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin , и пока этого достаточно для дурения и блокировок, и ютуба.

Тем не менее чисто профилактически в nfqws заменен дефольный ClientHello на версию от firefox 128 без kyber. Сделана рандомизация SNI в формате [a-z][a-z0-9]{5}\.(com|org|net|edu|gov|biz)
Так же рандомизируются поля random и session id.
Рандомизация применяется только к дефолтному фейку. Если указать внешний файл для фейка - он будет как есть. Рандомизация выполняется 1 раз при старте nfqws.

Пофиксены 2 проблемы на архитектуре mips64 : сломаный seccomp filter и threaded resolver в tpws

В mdig пофиксено отображение статистики на 32-битных архитектурах с 64-битным time_t

МНОЖЕСТВЕННЫЕ СТРАТЕГИИ
nfqws способен по-разному реагировать на различные запросы и применять разные стратегии дурения. Это реализовано посредством поддержки множества профилей дурения. Профили разделяются в командной строке параметром --new. Первый профиль создается автоматически.
Для него не нужно --new. Каждый профиль имеет фильтр. По умолчанию он пуст, то есть профиль удовлетворяет любым условиям. Фильтр может содержать жесткие параметры : версия ip протокола или порты tcp/udp. Они всегда однозначно идентифицируются даже на нулевой фазе десинхронизации, когда еще хост неизвестен. В качестве фильтра могут выступать и хост-листы. Они могут сочетаться с жесткими параметрами. При поступлении запроса идет проверка профилей в порядке от первого до последнего до достижения первого совпадения с фильтром. Жесткие параметры фильтра сверяются первыми. При несовпадении идет сразу же переход к следующему профилю. Если какой-то профиль удовлетворяет жесткому фильтру и содержит авто-хостлист, он выбирается сразу. Если профиль удовлетворяет жесткому фильтру, для него задан хостлист, и у нас еще нет имени хоста, идет переход к следующему профилю. В противном случае идет проверка по хостлистам этого профиля. Если имя хоста удовлетворяет листам, выбирается этот профиль. Иначе идет переход к следующему.
Может так случиться, что до получения имени хоста соединение идет по одному профилю, а при получении хоста профиль меняется на лету. Поэтому если у вас есть параметры дурения нулевой фазы, тщательно продумывайте что может произойти при переключении стратегии. Смотрите debug log, чтобы лучше понять что делает nfqws.
Нумерация профилей идет с 1 до N. Последним в цепочке создается пустой профиль с номером 0.
Он используется, когда никакие условия фильтров не совпали.

ВАЖНО : множественные стратегии создавались только для случаев, когда невозможно обьединить имеющиеся стратегии для разных ресурсов. Копирование стратегий из blockcheck для разных сайтов во множество профилей без понимания как они работают приведет к нагромождению параметров, которые все равно не покроют все возможные заблокированные ресурсы. Вы только увязните в этой каше.

Мульти-профиль для tpws будет позже.
Рефакторинг был серьезный, поэтому необходимо тестирование !

Несколько практических замечаний по поводу мульти-стратегий.
Если используются скрипты zapret, то в опции NFQWS сначала пишите специальные стратегии для особых доменов. После них пишите --new и дальше то, что было там раньше.
Все свои “фишки” типа стандартных листов / автолиста скрипты zapret добавляют в конец - к последнему профилю десинхронизации.

НЕСОВМЕСТИМОЕ ИЗМЕНЕНИЕ.
В новой концепции профилей методы нулевой фазы десинхронизации несовместимы с хост-листами и больше не применяются !
Ранее они применялись , игнорируя хостлист.
Если у вас были стратегии с syndata или wssize и включен режим hostlist, то syndata и wssize не будут применены. Остальные методы 1 и 2 фазы будут применены как обычно.
Если включен режим autohostlist, то syndata и wssize будут применяться, поскольку профиль с autohostlist приоритетен.

Пример :
NFQWS_OPT_DESYNC="--hostlist=/opt/zapret_lists/list-youtube.txt --dpi-desync=split2 --new --dpi-desync=fake,split --dpi-desync-ttl=0 --dpi-desync-fooling=datanoack" NFQWS_OPT_DESYNC_HTTPS6="--hostlist=/opt/zapret_lists/list-youtube.txt --dpi-desync=fake,split2 --dpi-desync-ttl=5 --dpi-desync-fooling=datanoack --dpi-desync-fake-tls=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin --new --dpi-desync=fake,split2 --dpi-desync-ttl=5 --dpi-desync-fooling=datanoack"

Вот так изменилось содержимое preset_russia.cmd для winws :
start "zapret: http,https,quic" /min "%~dp0winws.exe" --wf-tcp=80,443 --wf-udp=443 --filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=11 --new --filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --new --filter-tcp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls="%~dp0tls_clienthello_www_google_com.bin" --new --dpi-desync=fake,disorder2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig

windivert filter : это то, что захватывает ядро и передает процессу winws. Аналог ip/nf tables.
1 профиль : udp 443 - для quic
2 профиль : tcp port 80 - для http
3 профиль : tcp port 443 с листом list-youtube.txt . https для ютуба
4 профиль : все остальные https

Теперь продумайте логику как это работает.
Мы обрабатываем только порты 80 и 443 для tcp и порт 443 для udp.
Иного к нам не спустит windivert.

Если у нас порт udp 443, то применять fake.
Тут жесткая фиксация, udp на другой профиль попасть не может.

Если tcp port 80, то тут тоже все однозначно. Другой профиль невозможен

Если tcp port 443, то начало соединения на нулевой фазе идет по профилю 4.
Но т.к. нет методов нулевой фазы (wssize, syndata и тому подобное), то никаких действий не будет.
Как только получаем хостнейм из SNI, идет проверка заново по всем профилям.
1,2 профили отбрасываются , поскольку не удовлетворяют жесткому фильтру.
На 3 профиле идет проверка hostname по листу list-youtube.txt
Если хост в этом листе, выбирается профиль 3. Здесь происходит смена профиля на лету.
Иначе профиль остается как был - 4.

Посмотрим на preset_russia_autohostlist.cmd
start "zapret: http,https,quic" /min "%~dp0winws.exe" --wf-tcp=80,443 --wf-udp=443 --filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=11 --new --filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --hostlist-auto="%~dp0autohostlist.txt" --new --filter-tcp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls="%~dp0tls_clienthello_www_google_com.bin" --new --dpi-desync=fake,disorder2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --hostlist-auto="%~dp0autohostlist.txt"

Разница только в наличии параметра --hostlist-auto. Причем он подтянут сразу к 2 профилям : 2 и 4.
Можно делать разные автолисты для жестких профилей, но можно использовать и 1 файл.
Почему я написал 2 раза автолист ? Потому что сперва идет проверка жесткого фильтра. Если у нас порт 80, до профиля 4 мы не доберемся, и автолист не будет задействован.
Автолист всегда надо писать на последнем профиле, к которому может дойти проверка на жестком фильтре. Если таких путей несколько, и вы хотите автолист на всех, то и писать надо во все места.
Но если бы вы написали автолист на профиле 3, это была бы большая глупость.
До профиля 4 дело бы вообще не дошло, и все бы обслуживалось по профилю 3.

Теперь подумайте куда надо было бы написать wssize и syndata для https, если бы они были в стратегии. Правильный ответ - в профиль 4. Даже для ютуба, который идет по профилю 3. И они будут применятся ко всем сайтам, потому что не фильтруются по хостлисту.

А что будет со старыми конфигами ? Ничего не будет. Они так же будут работать по единственному профилю. За исключением упомянутого выше несовместимого изменения. Если в стратегии были syndata или wssize, и был задан режим hostlist, стратегия полностью или частично перестанет работать. Например, может пропасть ютубе на телике, но остаться на компе (тк TLS 1.2 перестал обходиться). В последнем случае меняйте стратегию или отказывайтесь от hostlist. Чтобы работало как раньше, надо было бы дописать еще один профиль c wssize/syndata, но уже после дополнительных параметров с листами, которые сформируют скрипты zapret. Пока это не реализовано в основном функционале, хотя может быть сделано через custom script.

Почему нельзя было бы сделать как раньше сразу ? Представьте такой вариант
--hostlist a --wssize 1:6 --new --hostlist b --wssize 2:5
хостнейм мы не знаем. что выбирать ?

Решение проблемы с несовместимостью wssize/syndata с MODE_FILTER=hostlist.

Добавлены переменные конфига

#NFQWS_OPT_DESYNC_SUFFIX="--dpi-desync=syndata"
#NFQWS_OPT_DESYNC_HTTP_SUFFIX="--dpi-desync=syndata"
#NFQWS_OPT_DESYNC_HTTPS_SUFFIX="--wssize 1:6"
#NFQWS_OPT_DESYNC_HTTP6_SUFFIX="--dpi-desync=syndata"
#NFQWS_OPT_DESYNC_HTTPS6_SUFFIX="--wssize 1:6"

Значения по умолчанию копируются в незаполненные специализированные версии аналогичным образом, как и в основных параметрах.
К параметрам nfqws добавляется --new <suffix_strategy>.
Итоговые параметры nfqws могут быть такими : <main_strategy> --hostlist=ipset/zapret-hosts-user.txt --new <suffix_strategy>

Реальный пример.
У вас раньше стояло так :

MODE_FILTER=hostlist
NFQWS_OPT_DESYNC_HTTPS="--dpi-desync=fake --dpi-desync-fooling=datanoack --wssize 1:6"

Это перестало работать.
Надо сделать так :

MODE_FILTER=hostlist
NFQWS_OPT_DESYNC_HTTPS="--dpi-desync=fake --dpi-desync-fooling=datanoack"
NFQWS_OPT_DESYNC_HTTPS_SUFFIX="--wssize 1:6"

Здесь вы явно указываете, что wssize применяется всегда, вне зависимости от хостлист фильтра.
Так было и раньше, но теперь старый вариант указания параметров не работает.
Менять запись нужно только если MODE_FILTER=hostlist. Если там что-то еще - не нужно. Наоборот, если вы уберете wssize из основных параметров и напишите в суффикс без MODE_FILTER=hostlist, то wssize опять перестанет работать, поскольку дело не дойдет до suffix профиля.

Чтобы wssize работал всегда вне зависимости от MODE_FILTER, можно написать так :

NFQWS_OPT_DESYNC_HTTPS="--dpi-desync=fake --dpi-desync-fooling=datanoack --wssize 1:6"
NFQWS_OPT_DESYNC_HTTPS_SUFFIX="--wssize 1:6"

tpws тоже переделан на множественные стратегии

Работают аналогично nfqws, кроме некоторых моментов.
Нет параметра --filter-udp, поскольку tpws udp не поддерживает.
Методы нулевой фазы (–mss) могут работать по хостлисту в одном единственном случае :
если используется режим socks и удаленный ресолвинг хостов через прокси.
То есть работоспособность вашей настройки в одном и том же режиме может зависеть от того,
применяет ли клиент удаленный ресолвинг. Это может быть неочевидно.
В одной программе работает, в другой - нет.
Если вы используете профиль с хостлистом , и вам нужен mss, укажите mss в профиле с хостлистом,
создайте еще один профиль без хостлиста, если его еще нет, и в нем еще раз укажите mss.
Тогда при любом раскладе будет выполняться mss.
Используйте curl --socks5 и curl --socks5-hostname для проверки вашей стратегии.
Смотрите вывод --debug, чтобы убедиться в правильности настроек.

В стандартных скриптах запуска --mss так же копируется в suffix и используется оттуда при MODE_FILTER=hostlist.

MODE_FILTER=hostlist
TPWS_OPT="--hostspell=HOST --split-http-req=method --split-pos=3 --oob --mss 88"
TPWS_OPT_SUFFIX="--mss 88"

Это несовместимое изменение 1.
Несовместимое изменение 2 - удалена опция --mss-pf за ненадобностью. Функция реализована через профили.

В blockcheck внесена поддержка переменных
TPWS_EXTRA - для tpws
PKTWS_EXTRA - для nfqws/dvtws/winws
эти переменные добавляются к параметрам тестовых запусков соотв демонов

основное применение - включение разных внешних пейлоадов

PKTWS_EXTRA="--dpi-desync-fake-tls=/opt/zapret/files/fake/tls_clienthello_www_google_com.bin" ./blockcheck.sh

чтобы не уродовать код скрипта ради сиюминутных частных веяний и хотелок

Дополнение к *_EXTRA.

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

Допустим, у нас PKTWS_EXTRA=“–hostcase --hostnospace”
Я передаю эту переменную как есть $PKTWS_EXTRA без кавычек в дочерний процесс.
Получается 2 аргумента. Все хорошо.

но что делать, если PKTWS_EXTRA=“–hostcase --dpi-desync-fake-tls=”/opt/xxxx xxx xxx/fake.bin""

Нельзя никак сделать, чтобы стало 2 аргумента. И так, и сяк пробовал. Нет нормального способа разделить корректно. Будет или 1 аргумент, или огрызки, или будут передаваться кавычки как есть в процесс. А это - неправильно и не сработает.

Возможно, есть решение через какие-то внешние стандартные команды, но скрипт затачивается на огрызочный busybox environment. Там нет ничего advanced. И баша тоже нет.

Решение такое

PKTWS_EXTRA остается
В него можно совать аргументы через пробел, где в отдельно взятом аргументе нет пробелов.
Если пробелы есть или просто так по желанию можно использовать PKTWS_EXTRA_1 , PKTWS_EXTRA_2, … , PKTWS_EXTRA_9

корректно будет так :

PKTWS_EXTRA_1=“–hostcase” PKTWS_EXTRA_2=“–dpi-desync-fake-tls=/opt/xxxx xxx xxx/fake.bin” ./blockcheck.sh

Если у вас cygwin, то обратные слэши не подходят. Надо обратные слэши в пути перевернуть в прямые. Или использовать cygwin пути : /cygdrive/x/path/to/file.bin.
В скриптах для автоматизации конверсии путей надо использовать команду cygpath.
Пример cygpath есть в blockcheck.cmd

Аналогичная схема реализована и для TPWS_EXTRA