Find a file
Kirill Minovsky 6337df1556 refactor(core): prune the public surface nothing outside the crate names
A library crate cannot see a dead `pub` item, so the list came from an audit and
every removal was checked by the compiler:

* `dns/mod.rs` re-exported 30 names; only `query_doh_txt`, `resolve_host` and
  `parse_socks_proxy` are used through the flat path — callers spell out
  `dns::availability::…`, `dns::udp::…`. The others are gone.
* `probe::connector`: `new_insecure`, `new_verifying` and the argument-less
  `new_insecure_tls13`/`_tls12` had no caller (only the `_with` variants are used,
  by `domains.rs` and `burst.rs`), and `DpiTlsConnector`/`RustlsConnector` are named
  only inside `dpi-core` — both demoted to `pub(crate)`.
* `DpiProbeStream::{into_inner, get_ref, get_mut}`, `QTYPE_{NS,SOA,PTR,MX}` and
  `Language::{code, name, is_rtl}`: no caller anywhere.
* `profile`: `default_resolvers`, `default_doh` and `blockpage_signatures` were read
  only by a test asserting they are non-empty, and a test that only checks a list is
  non-empty pins nothing. `default_domains` stays — it is what the CLI uses when no
  `-d` is given. With `probe/tls.rs` gone, no path looked at the blockpage markers
  either; they live in git history until something reads them.
* `net::cert_compression::covers` guards the ClientHello profiles from a test and is
  called by nothing on a live connection: `#[cfg(test)]`.
* `create_insecure_dpi_tls_config_tls13/_tls12` stay `pub`: `examples/tls_fingerprint.rs`
  is a separate crate and consumes them.
* `#![warn(unreachable_pub)]` in the crate root so the surface cannot creep back.
2026-09-14 01:08:54 +03:00
.cargo build: vendor patched rustls, h2/compression features, release-local profile 2026-09-13 19:41:43 +03:00
.github/workflows chore: release v5.0.0-alpha.8 (UPX for routers, low-space auto-selection) 2026-09-07 20:21:12 +03:00
crates refactor(core): prune the public surface nothing outside the crate names 2026-09-14 01:08:54 +03:00
docs docs: mark the two decided items as done in the plan 2026-09-14 00:59:02 +03:00
vendor/rustls chore: untrack the rustls build directory a cargo check left behind 2026-09-13 22:13:59 +03:00
.gitignore chore: keep run exports out of git 2026-09-13 22:32:39 +03:00
Cargo.lock perf(tls): decode compressed certificates without brotli's encoder 2026-09-13 23:21:42 +03:00
Cargo.toml perf(tls): decode compressed certificates without brotli's encoder 2026-09-13 23:21:42 +03:00
config.yml docs(comments): describe behaviour instead of the retired prototype 2026-09-14 00:48:42 +03:00
Cross.toml fix(ci): use edge container for aarch64-linux-android and clean job names in release workflow 2026-09-05 01:38:47 +03:00
domains.txt chore: ignore the crash log, drop a dead domain from the list 2026-09-13 19:43:48 +03:00
install.ps1 release: 5.0.0-alpha.11 2026-09-13 21:50:34 +03:00
install.sh release: 5.0.0-alpha.11 2026-09-13 21:50:34 +03:00
README.md docs: stop presenting the JSON shape and the badges as a frozen contract 2026-09-14 00:46:44 +03:00
tcp16.json feat: Native Rust engine (v4.2.0) 2026-09-04 00:15:58 +03:00
whitelist_sni.txt feat: Native Rust engine (v4.2.0) 2026-09-04 00:15:58 +03:00


"Маяк у гаснущего горизонта свободного интернета"
Сквозь цифровые сумерки. Смотритель маяка, Runni

🦀 DPI Detector (Native Rust Engine)

Language: Rust License: MIT Release Telegram

Нативный инструмент для анализа цензуры и блокировок трафика на чистом Rust:

  • Никаких внешних зависимостей: без сторонних рантаймов, без C/C++ библиотек и системного OpenSSL — только rustls, ring и RustCrypto.
  • Легковесный: статический бинарник ≈3.9 МБ (4–6 МБ на роутерных сборках, UPX — ≈1.4 МБ), потребление оперативной памяти в работе — 3–6 МБ RAM.
  • Максимальная кросс-платформенность: нативная поддержка роутеров (MIPS, ARM), Windows (от Windows 7 до 11), Linux musl, macOS и Android (Termux).
  • Интерактивный 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:

  1. Автоматически находит директорию /opt/bin (Entware) и устанавливает бинарник туда (сохраняется после перезагрузки).
  2. Контролирует свободное место: если на накопителе осталось < 7 МБ, скрипт автоматически скачивает компактную версию со сжатием UPX (~1.4 МБ вместо ~3.9 МБ), защищая роутер от переполнения Flash или tmpfs.
  3. Заменяет файл атомарно (.tmp.$$ -> dpi-detector) с проверкой архитектуры через --version (при сбое UPX автоматически переключается на стандартный бинарник).
  4. Поддерживает принудительный выбор версии: DPI_UPX=1 (компактная) или DPI_UPX=0 (стандартная).
  5. Поддерживает запуск напрямую через 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')
      --json                     Вывод в машиночитаемом JSON
  -v, --verbose                  Подробное / отладочное логирование
  -l, --lang <LANG>              Язык интерфейса (ru, en, zh, fa, auto). По умолчанию auto
      --profile <PROFILE>        Региональный профиль цензуры (ru, ir, cn, global) [по умолчанию: ru]
      --legend                   Показать легенду статусов и выйти
  -p, --proxy <URL>              URL SOCKS5-прокси (socks5://127.0.0.1:1080)
  -c, --concurrency <N>          Лимит параллельных запросов
  -d, --domain <DOMAIN>          Конкретные домены для проверки (флаг можно повторять: -d vk.com -d ya.ru)
  -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) остаются латиницей в любом языке — так цифры, IP-адреса и строки логов читаются одинаково во всех локалях.

Номера доступных тестов:

  • 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 этого прогона).


🧩 Структура проекта

crates/
├── dpi-core/          # движок: протоколы, зондирование, классификация
│   ├── classify/      #   DpiProbeStream и вердикты: код ОС/TLS + стадия -> DpiStatus
│   ├── dns/           #   RFC 1035 wire, UDP, DoH, DoT, SOCKS5 UDP relay, тест 1
│   ├── net/           #   TCP/TLS-примитивы, отпечатки ClientHello (JA3/JA4, PQ),
│   │                  #   запросы к системе (адаптеры, маршруты, DNS, публичный IP)
│   ├── probe/         #   7 диагностических тестов и их общие примитивы
│   ├── config.rs      #   загрузка и нормализация config.yml
│   ├── profile/       #   региональные профили цензуры (ru, ir, cn, global)
│   └── i18n/          #   все тексты интерфейса (En, Ru, Zh, Fa)
└── dpi-detector/      # CLI: аргументы, TUI, таблицы, машинный вывод

Движок ничего не знает об интерфейсе: он возвращает типизированные отчёты и канонические токены вердиктов, а тексты, таблицы и JSON собирает бинарник.

🏗️ Сборка из исходников

Для самостоятельной сборки потребуется установленный 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

Перед коммитом прогоняются обе проверки репозитория:

cargo test --workspace
cargo clippy --workspace --all-targets