Test 2 pins one version per phase, and rustls writes `supported_versions` from the config, so a browser profile advertises `[GREASE, 0x0304]` where the Chrome 107 it imitates sends `[GREASE, 0x0304, 0x0303]` -- `[0x0304]` against `[0x0304, 0x0303]` for Firefox, which greases nothing. JA3 and JA4 cannot see it (they hash extension codes and the maximum version), so the pinned bundle hashes still match, but a middlebox reading the body can. It is kept: one hello per stack is what makes the TLS 1.3 column a TLS 1.3 verdict, since a hello offering both would let the server choose. Written next to the builders that pin, and asserted in the test that pins the lists, so it cannot drift unnoticed either way. |
||
|---|---|---|
| .cargo | ||
| .github/workflows | ||
| crates | ||
| docs | ||
| vendor/rustls | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| config.yml | ||
| Cross.toml | ||
| domains.txt | ||
| install.ps1 | ||
| install.sh | ||
| README.md | ||
| tcp16.json | ||
| whitelist_sni.txt | ||
"Маяк у гаснущего горизонта свободного интернета"
Сквозь цифровые сумерки. Смотритель маяка, Runni
🦀 DPI Detector (Native Rust Engine)
Полностью переписанный нативный инструмент для анализа цензуры и блокировок трафика на чистом Rust:
- 0 зависимостей: Никакого Python, C/C++ библиотек или системного OpenSSL. Собрано на
rustls,ringиRustCrypto. - Легковесный: Размер бинарника всего ~3.2 МБ, потребление оперативной памяти в работе — 3–6 МБ RAM.
- Максимальная кросс-платформенность: Нативная поддержка роутеров (MIPS, ARM), Windows (от Windows 7 до 11), Linux musl и macOS.
- Интерактивный TUI + Batch: Полноценное стрелочное меню в терминале и быстрый тихий запуск при передаче аргументов командной строки.
🚀 Быстрый запуск в 1 строку (Без установки)
🐧 Linux, macOS, роутеры Keenetic, OpenWrt & Entware
curl -fsSL https://raw.githubusercontent.com/Runnin4ik/dpi-detector/rust/install.sh | sh
📱 Android (Termux)
curl -fsSL https://raw.githubusercontent.com/Runnin4ik/dpi-detector/rust/install.sh | sh
Скрипт автоматически определит Termux, установит нативный Android-бинарник в $PREFIX/bin/dpi-detector и запустит его. Для повторного запуска достаточно ввести dpi-detector.
🪟 Windows (PowerShell)
irm https://raw.githubusercontent.com/Runnin4ik/dpi-detector/rust/install.ps1 | iex
📦 Готовые бинарные сборки
Все сборки полностью статичны и не требуют внешних библиотек:
| Платформа / Устройство | Архитектура | Бинарник в релизах |
|---|---|---|
| Windows 10, 11, Server | x86_64 | dpi-detector-windows-x86_64.exe |
| Windows 7, 8, Server 2008/2012 | x86_64 | dpi-detector-windows-7-x86_64.exe |
| Linux (PC, Серверы, VPS) | x86_64 musl | dpi-detector-linux-x86_64 |
| Роутеры ARM64 (Keenetic Hopper/Titan 2, RPi, OpenWrt) | aarch64 musl | dpi-detector-linux-arm64 |
| Роутеры ARMv7 (Keenetic Titan 1/Hero, Asus RT-AX58U) | armv7hf musl | dpi-detector-linux-armv7 (и -upx) |
| Роутеры MIPS LE (Keenetic Viva/Giga, MT7621, OpenWrt) | mipsel musl | dpi-detector-linux-mipsel (и -upx) |
| Роутеры MIPS BE (Atheros, Qualcomm, OpenWrt) | mips musl | dpi-detector-linux-mips (и -upx) |
| macOS Apple Silicon (M1, M2, M3, M4) | aarch64 | dpi-detector-macos-arm64 |
| macOS Intel | x86_64 | dpi-detector-macos-intel |
| Android ARM64 (Смартфоны, планшеты, Termux, ADB) | aarch64 bionic | dpi-detector-android-arm64 |
| Android ARM32 (Старые устройства, Android TV) | armv7 bionic | dpi-detector-android-armv7 |
🛠️ Установка на роутеры (Keenetic / OpenWrt / Entware)
При запуске на роутере скрипт install.sh:
- Автоматически находит директорию
/opt/bin(Entware) и устанавливает бинарник туда (сохраняется после перезагрузки). - Контролирует свободное место: если на накопителе осталось
< 7 МБ, скрипт автоматически скачивает компактную версию со сжатием UPX (~1.4 МБ вместо ~3.9 МБ), защищая роутер от переполнения Flash илиtmpfs. - Заменяет файл атомарно (
.tmp.$$->dpi-detector) с проверкой архитектуры через--version(при сбое UPX автоматически переключается на стандартный бинарник). - Поддерживает принудительный выбор версии:
DPI_UPX=1(компактная) илиDPI_UPX=0(стандартная). - Поддерживает запуск напрямую через SSH:
# Установка и запуск меню
curl -fsSL https://raw.githubusercontent.com/Runnin4ik/dpi-detector/rust/install.sh | sh
# Повторный запуск после установки
/opt/bin/dpi-detector
⚙️ Параметры командной строки (CLI)
Использование: dpi-detector [ОПЦИИ]
Опции:
-t, --tests <TESTS> Номера тестов ('012', '1', '2' или "1,2,3")
--json Вывод в машиночитаемом JSON
-v, --verbose Подробное / отладочное логирование
-l, --lang <LANG> Язык интерфейса (ru, en, zh, fa, auto). По умолчанию auto
--profile <PROFILE> Региональный профиль цензуры (ru, ir, cn, global)
--legend Показать легенду статусов и выйти
-p, --proxy <URL> URL SOCKS5-прокси (socks5://127.0.0.1:1080)
-c, --concurrency <N> Лимит параллельных запросов
-d, --domain <DOMAIN> Тестируемый домен (флаг можно повторять)
-o, --output <PATH> Путь к файлу отчёта
--domains <PATH> Путь к файлу со списком доменов
--tcp16 <PATH> Путь к файлу целей TCP16
--ascii Только ASCII для старых консолей (без Unicode-глифов и рамок)
--fingerprint <PROFILE> Профиль отпечатка TLS ClientHello (rustls|custom|chrome|safari). custom — форма Firefox 133, chrome — Chrome 107 / Edge 99-101, safari — Safari 15.5-18.4 из curl-impersonate; все предлагают h2
--burst <N> Fingerprint/Сибирская блокировка (тест 6): одновременных запросов за раунд [по умолчанию: 4]
--burst-timeout <SECONDS> Тест 6: таймаут одного рукопожатия, секунды [по умолчанию: 8]
--burst-profiles <LIST> Fingerprint для теста 6: all|rustls,custom(firefox133),chrome(chrome107),safari(safari155) [по умолчанию: all]
--burst-tls <VERSION> Версия TLS для теста 6: 1.2|1.3 [по умолчанию: 1.3]
--burst-alpn <PROTOCOL> ALPN для теста 6: h2 (предлагает h2 с откатом на http/1.1)|http/1.1 (только http/1.1) [по умолчанию: h2]
-h, --help Показать справку
-V, --version Показать версию
Справка и все сообщения локализованы: dpi-detector --lang en --help, --lang zh --help, --lang fa --help. Любой другой текст интерфейса - таблицы, легенда, предупреждения - тоже следует за --lang; --json не зависит от языка (ключи и значения detail остаются каноническими).
Локализация (crates/dpi-core/src/i18n)
Messages- по одному полю на строку, четыре блока (En,Ru,Zh,Fa); шаблоны используют{}.legend_sections*()- таблицы--legend;details.rs- перевод канонических деталейDET_*(русский - исходный язык, выводится как есть).- Язык Farsi рендерится Finglish (латиница, без персидской графики и диакритики).
- Статусные бейджи и протоколы (
OK,BLOCKED,TLS RST,SNI,ClientHello) не переводятся никогда.
Номера доступных тестов:
0— Информация о сети и системе (внешний IP, провайдер, AS, страна, тип NAT)1— Доступность DNS-серверов (проверка UDP 53, DoH Cloudflare/Google/Quad9/Yandex/AdGuard)2— Доступность сайтов (HTTP, TLS 1.2, TLS 1.3, классификация блокировок DPI)3— Доступность CDN и хостингов (тест 16 KB) (детект сброса соединений после 14–34 КБ данных)4— Поиск белых SNI (перебор рабочих SNI для заблокированных AS: цель отбирается по 16 KB-обрыву, TLS RST и TLS DROP)5— Доступность Telegram (проверка доступности и скорости датацентров DC1–DC5)6— Fingerprint/Сибирская блокировка (N одновременных TLS-рукопожатий на один домен выбранными отпечатками: сколько ответили и что именно перестало отвечать)7— Легенда статусов (справка по вердиктам)
Тест 6: Fingerprint/Сибирская блокировка
При выборе теста 6 открывается свой экран настроек: число одновременных рукопожатий, таймаут одного рукопожатия в секундах, версия TLS (1.2/1.3), протокол HTTP в ALPN (h2 — как у браузеров, с откатом на http/1.1, или http/1.1 — только он), домен (в поле показан хост, который проверял прошлый прогон; первый набранный символ заменяет его, а пустое поле — весь список, как в тесте 2; вставленный URL приводится к имени хоста тем же очистителем, что и список из конфига) и Fingerprint (по умолчанию все). Поле домена подсвечивается: серый фон — строка выбрана, синий — в поле идёт ввод. Q/Esc отменяет тест.
На каждый домен и отпечаток выполняется N одновременных рукопожатий выбранной версии TLS — отдельные TCP-соединения, свежие сессии без resumption. Две оси дают 4 комбинации, и они измеряют разные вещи: 1.3 против 1.2 — реакцию на версию протокола, h2 против http/1.1 — реакцию на ALPN (некоторые триггеры срабатывают именно на h2-хелло; JA4 при этом меняет поле ALPN, h2 → h1). В таблице M/N по каждому отпечатку (зелёный — ответили все, жёлтый — часть, красный — никто), в колонке «Детали» — самый частый вердикт отказа (TLS RST, TLS DROP, SYN DROP, …). Тест идёт последним: серия рукопожатий может «сжечь» цель на время, и измерения после неё недействительны.
Во время прогона печатается одна живая строка Тестируем: CHROME 107 3/4 12/35 · 00:04 — какая форма сейчас в эфире, который это раунд из скольких, сколько хостов раунда готово и сколько идёт время. Отдельной шапки с настройками и блок «Итог» тест не выводит: отпечаток с версией и так виден в колонках таблицы, а пустой итог не рисуется.
Из неинтерактивного запуска настройки задаются флагами --burst, --burst-timeout, --burst-profiles, --burst-tls, --burst-alpn; в --json результат лежит в аддитивном ключе results.fingerprint_burst (вместе с tls и alpn этого прогона).
🏗️ Сборка из исходников
Для самостоятельной сборки потребуется установленный Rust (версии 1.80+):
git clone https://github.com/Runnin4ik/dpi-detector.git -b rust
cd dpi-detector
cargo build --release -p dpi-detector
Скомпилированный бинарник будет находиться в target/release/dpi-detector (dpi-detector.exe на Windows).
Для статической сборки под Windows без внешних зависимостей CRT:
RUSTFLAGS="-C target-feature=+crt-static" cargo build --release -p dpi-detector