github RixyPow/netzapret v0.5.7
NetZapret 0.5.7

latest releases: v1.2.0, v1.1.1, v1.1.0...
one month ago

«Напрямую» теперь и правда напрямую

Прежде этот выбор означал только «мимо туннеля». Для winws2 он ничем
не отличался от «десинка»: имя всё равно попадало в секцию пресета
и получало рецепт. Снаружи выглядело так, будто переключатель не работает, —
и один такой случай стоил вечера разбора: у части Discord стояло
«напрямую», а к discord.media применялся send + syndata из пресета.

Теперь имена таких правил уходят в тот же список исключений, что и прибитые
в файле hosts. Источника два, означают они одно — «этому имени вмешательство
не нужно», — и список поэтому один.

Перекрытые правила в него не попадают. Порядок решает всё: правило может
быть перекрыто более ранним, и тогда имя живёт по чужому режиму. У Discord
так и вышло — «обновления» стоят на «напрямую», но до них имя забирает
список сайта, стоящий выше и покрывающий ту же зону. Записав его
в исключения, мы отменили бы десинк там, где его никто не отменял.

Это меняет поведение у тех, кто уже ставил «напрямую». Раньше выбор
ничего не делал, теперь делает. Если какое-то имя работало именно потому,
что пресет его всё-таки чинил, — верните ему «десинк».

Голос Discord ломала сама программа, а не пресет

Симптом — бесконечное «Подключение к RTC», затем «не установлен маршрут»,
при полностью работающем сайте. Нашлось это так: на том же самом пресете,
запущенном сторонней программой, голос работал. Один пресет, разный
результат — значит дело в запуске.

Сравнение вышло коротким:

строк в файле пресета    428
аргументов у нас         479
потеряно из файла          0
добавлено          --hostlist-exclude × 51

Ни одной строки мы не теряли — только вставляли. Список имён, которые
десинку трогать нельзя, уходил в каждый профиль подряд.

Вред у лишнего ключа оказался ровно там, где болело. Исключение написано
именами, а три секции Discord отбирают трафик не по ним: «Голосовые
звонки/чаты» — по классификатору stun,discord, «Discord UDP» и запасное
правило — по спискам адресов. Имени в таких пакетах не бывает никогда,
сверять не с чем. Зато профиль от этого ключа становится хостлистовым,
а такой ждёт разобранного имени — и пакет без имени ему уже не достаётся.

В журнале это видно и косвенно: профиль Discord UDP срабатывал только
на QUIC, у которого есть SNI, и ни разу на чём-либо без имени. Профиль
Голосовые звонки/чаты не срабатывал вовсе. Клиент за всё время наблюдения
пять раз достучался до голосового шлюза по TCP и не отправил ни одного
UDP-пакета: адрес для них приходит ответом на кадр, до которого дело
не доходило.

Теперь исключение получают только секции с --hostlist либо
--hostlist-domains. На Universal V6 ключей стало 40 вместо 51, на V8 —
45 вместо 56. Свои профили получают его как прежде: они по именам
и работают.

Голосовые секции пресетов при этом не тронуты и совпадают с прежними
построчно. Менять их не пришлось.

Выбранный рецепт мог пропасть молча

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

Тихо, что хуже всего: ненайденный рецепт означает пустой набор шагов,
профиль без шагов не выпускается вовсе, и настройка просто не применяется.
В меню при этом честно написано «десинк: hostfakesplit_multi».

Теперь рецепт ищется и среди имён групп, и среди секций внутри них,
а не найденный — пишется в журнал строкой с именем рецепта, именем пресета
и числом затронутых имён. Молчание тут и было главной бедой: сама поломка
на одну строку, а искали её три захода.

Свой профиль берёт порты у секции пресета

Было зашито 80,443. У Discord секции объявлены на восьми портах, и пять
из них — запасные HTTPS у Cloudflare: 2053,2083,2087,2096,8443. Клиент
переходит на них сам, когда сеть ведёт себя плохо, то есть ровно в тех
условиях, ради которых обход и нужен.

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

Проверка рецептов у голоса

Не запускалась вовсе. Для замера бралась первая запись списка, а в
discord-media.txt она одна — сам discord.media, единственное имя зоны,
которое из-под фильтра выпадает. Проверка честно отвечала «рецепт не нужен».

Настоящее имя в каталог не впишешь: голосовые серверы выдаются под звонок,
и frankfurt1234.discord.media не разрешается ни у кого. Поэтому имя
для пробы задаёт каталог, а сама проба больше не спрашивает DNS: адрес
берётся у ближайшего предка, который разрешается, а имя уходит в SNI.
Списки winws2 сопоставляются по зонам, так что профиль встаёт тот же, что
на настоящий голосовой сервер.

Из перебора убраны секции по UDP. Рецепт проверяется рукопожатием TLS,
а ему в UDP проверять нечего: приём получал «не помогает» независимо
от собственных достоинств и стоял в списке наравне с работающими. Отбор
идёт по названному транспорту — секция без фильтров ловит всё подряд,
TCP в том числе.

Камуфляж голоса на весь звонок

У секции Discord UDP, через которую идёт сам звук, снято окно -n8
и рецепт заменён на udplen. Прежнее окно держало камуфляж на первых
девяти пакетах, дальше звонок шёл голым до конца.

Замер до правки: пинг 29 мс, ноль потерь и ноль ошибок расшифровки первые
две минуты, затем качели 200–2000 мс волнами — при нулевых Decryption Failures и Routing Failures. Пакеты не портятся, их задерживают: так
выглядит переклассификация потока, когда камуфляж кончился.

Окно и рецепт менялись вместе, и это обязательно: fake:repeats=10
на каждом пакете звонка дал бы десятикратный трафик и джиттер хуже
исходного. udplen ничего не дублирует и не переставляет — дописывает
два байта к payload от 64 байт, меняя длину, но не тайминг.

Секцию выбирали по --payload, а не по названию: соседняя «Голосовые
звонки/чаты» берёт только stun и discord_ip_discovery, то есть
установление связи, а не поток.

На живом звонке эта правка не подтверждена. Если пойдут Decryption Failures — udplen ломает SRTP, и надо возвращать fake:blob=quic_google
с -n8. Откат записан в комментарии самой секции.

Проверка блокировок: меньше шума

Маркеры зон больше не попадают в таблицу. Записи A у scdn.co,
playstation.net, nintendo.net, slack-edge.com,
dropboxusercontent.com нет и не было ни у кого: работают только
поддомены, а само имя стоит в списке, чтобы покрыть зону целиком. Строка
«нет адреса у имени» среди закрытого сбивает — её начинают чинить.

Из списков такие имена не убраны: там они несут работу, а не показ. Убери
scdn.co из spotify.txt — и десинк перестанет применяться ко всей сети
доставки Spotify. Пропущенные считаются и называются под таблицей отдельной
строкой, чтобы их отсутствие не было тихим.

Отказ по стране стал жёлтым вместо красного. Красный ставил его в один ряд
с закрытым наглухо, а это работающая связь: ответ пришёл, и пришёл от самого
сайта. Лечится он не рецептом, а выходом в другой стране.

Пресет «Universal V8 diag»

Временный, для замера. Тот же V8 плюс diag_once в пяти секциях Discord:
строка на соединение — протокол, порты, адрес назначения, имя из SNI,
класс L7. Пакеты не трогает.

Плюс секция-ловушка на голосовой UDP в самом конце. Стоит последней
намеренно: первый совпавший профиль забирает пакет, и встань она раньше —
отобрала бы голос у секции выше. Пусто в ней — адрес голосового сервера
есть в списке и его забрали раньше; есть строки — список устарел и трафик
идёт мимо всех правил.

Журнал отдельный, diag-discord.log рядом с winws2.exe: --debug пишет
решение по каждому пакету, и минута звонка вытеснила бы из общего журнала
как раз то, ради чего он снимался.

Чем это собрано и как сверить

NetZapret.zip   D918922F3DC33C50FD96CFD7BE0071F81D0E2756AF5AFCDA034601210D295345
NetZapret.exe   B8E8038F8710B7C6DA889335A6C5FE2A71159490F469965CEF32BE1A7FFF31BD

Пакет SDK .NET 8.0.424, сборка Release, win-x64, self-contained, один файл.

Проверить скачанное:

Get-FileHash NetZapret.zip -Algorithm SHA256

Собрать самому и сравнить:

git checkout v0.5.7
pack.cmd

Совпасть должен NetZapret.exe. Архив — нет: в нём лежат winws2 и sing-box,
собранные не нами, и их версии у вас могут отличаться.

Don't miss a new netzapret release

NewReleases is sending notifications on new releases.