RKN Block Checker

Небольшой CLI-инструмент, определяющий, находится ли ваше подключение в зоне блокировки РКН/ТСПУ, и, что полезнее, какой именно тип блокировки применяется (отравление DNS, TCP RST, DPI TLS по SNI или подстановочная страница оператора).

Смысл не в том, чтобы узнать, что «сайт X не открывается», — браузер и так это скажет. Смысл в том, чтобы независимо проверить каждый уровень сетевого стека и сообщить, где именно произошёл сбой. Это даёт гораздо больше информации о вашей ситуации, чем стандартная страница «сайт недоступен».

Быстрый старт

pip install rkn-block-checker
rkn-check

Всё. Инструмент зондирует встроенный список сайтов, классифицирует каждый сбой по уровню и выдаёт заключение. Никакой настройки не требуется.

Пример вывода

======================================================================
  RKN Block Checker
======================================================================
  IP:       95.165.xxx.xxx
  ISP:      AS12389 Ростелеком
  Location: Москва, Москва, RU
----------------------------------------------------------------------

Белый список (должны всегда работать)
  название         вердикт                   TCP     TLS     PLT  статус
  --------------------------------------------------------------------
  gosuslugi        ✓ OK                      18ms    42ms   380ms  200
  yandex           ✓ OK                       8ms    25ms    95ms  200
  sberbank         ✓ OK                      12ms    38ms   250ms  200
  vk               ✓ OK                       9ms    28ms   180ms  200
  ...

Чёрный список (ограниченные РКН)
  название         вердикт                   TCP     TLS     PLT  статус
  --------------------------------------------------------------------
  instagram        ~ ВЕРОЯТНО TLS DPI        22ms       -       -  -
    └ Сброс TLS сразу после ClientHello — соответствует DPI по SNI
  twitter/x        ~ ВЕРОЯТНО TLS DPI        24ms       -       -  -
    └ TLS handshake молча оборван — соответствует DPI-фильтрации
  rutracker        ✗ HTTP STUB               18ms    45ms   120ms  200
    └ Тело ответа совпадает с известной подстановочной страницей оператора
  protonvpn        ✗ DNS                        -       -       -  -
    └ Системный DNS не резолвит, DoH резолвит — соответствует отравлению DNS

======================================================================
  Сводка
----------------------------------------------------------------------
  Белый список: 21/21 работают
  Чёрный список: 3/15 открыты, 12/15 заблокированы

  → Вероятно, нахождение в зоне блокировки РКН (средняя уверенность).
    Большинство сбоев в чёрном списке соответствуют шаблонам цензуры (TLS DPI, TCP RST),
    но эти сигналы также могут быть вызваны проблемами на стороне сервера.
    Для подтверждения нужна контрольная точка.

  Типы блокировок в чёрном списке:
    ~ ВЕРОЯТНО TLS DPI: 8
    ✗ DNS: 2
    ✗ HTTP STUB: 2
======================================================================

Метки вердиктов откалиброваны по степени уверенности:

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

Примечание об использовании примеров: Фактические данные (IP, ISP, списки сайтов, вердикты) в выводе — это примеры. При реальном запуске инструмента значения будут соответствовать вашему подключению и текущей ситуации в сети.

Зачем это нужно

Если сайт не открывается, браузер сообщит об этом. Но чтобы предпринять какие-либо действия (выбрать правильный инструмент обхода, составить полезный отчёт об ошибке или просто понять, что происходит с вашим трафиком), нужно знать, на каком именно уровне сетевого стека происходит вмешательство.

Разные механизмы цензуры оставляют разные «отпечатки»:

`rkn-check` последовательно проходит DNS → TCP → TLS → HTTP для каждой цели и останавливается на первом же сбое. Уровень, на котором произошёл сбой, становится вердиктом.

Типовые сценарии

Просто диагностировать текущее подключение

rkn-check

Зондирует встроенные списки (~21 контрольный сайт, ~15 ограниченных РКН), выдаёт отчёт по каждому сайту и сводное заключение.

Проверить один URL

rkn-check --url https://example.com
rkn-check --url example.com --url google.com    # повторить для нескольких

Полностью пропускает встроенные списки и выполняет ad-hoc проверку только переданных URL. Сводного заключения нет — не с чем сравнивать. Используйте, когда нужно узнать, «открылся ли этот конкретный сайт?», не тратя время на полное сканирование.

Передать вывод в `jq`

# имена всех заблокированных сайтов
rkn-check --json | jq -r '.blacklist[] | select(.verdict != "OK") | .name'
 
# подсчёт по типу блокировки
rkn-check --json | jq '.blacklist | group_by(.verdict) | map({verdict: .[0].verdict, count: length})'
 
# только DPI-блокировки (TCP работает, TLS умирает)
rkn-check --json | jq '.blacklist[] | select(.verdict == "TLS_BLOCK" and .tcp_ok)'

Использовать собственные списки целей

rkn-check --black-file my-list.txt
rkn-check --white-file my-control.json --black-file my-targets.json

См. раздел Пользовательские списки целей.

Запускать из cron и сохранять JSON с течением времени

rkn-check --json --no-self-info > "snapshots/$(date -I).json"

`–no-self-info` пропускает определение публичного IP, чтобы инструмент не обращался к `ipinfo.io` при каждом запуске cron (и чтобы результирующий JSON не содержал ваш IP).

Использование

rkn-check [-h] [--json] [--white] [--black]
          [--white-file PATH] [--black-file PATH] [--url URL]
          [--timeout TIMEOUT] [--workers WORKERS] [-v]
          [--no-self-info] [--identify]
Флаг Что делает
`–json` Выдать machine-readable JSON вместо цветного отчёта.
`–white` Проверить только контрольные цели (белый список).
`–black` Проверить только цели из чёрного списка.
`–white-file PATH` Заменить встроенный белый список файлом `.txt` или `.json`.
`–black-file PATH` Заменить встроенный чёрный список файлом `.txt` или `.json`.
`–url URL` Зондировать один URL или имя хоста; повторите для нескольких. Пропускает встроенные списки.
`–timeout T` Таймаут на одно зондирование в секундах (по умолчанию 5.0).
`–workers N` Размер пула потоков для параллельных проверок (по умолчанию 10).
`–no-self-info` Пропустить определение публичного IP в начале отчёта.
`–identify` Отправлять самоидентифицирующий User-Agent вместо обычного Chrome. См. Конфиденциальность и модель угроз.
`-v` / `-vv` Логирование на уровне INFO / DEBUG.

`–white` и `–black` взаимно исключают друг друга. `–url` нельзя комбинировать с `–white`/`–black`/`–white-file`/`–black-file` — в ad-hoc режиме проверяются только переданные URL.

Как это работает

Для каждой цели инструмент проходит DNS → TCP → TLS → HTTP и останавливается на первом сбое. Уровень сбоя становится вердиктом.

Уровень Зонд Что означает сбой
DNS Системный резолвер против Cloudflare DoH, сравнение полных наборов адресов Наборы совпадают, но системный резолвер не работает один → отравление DNS. Непересекающиеся наборы → прозрачная подмена (rewriting).
TCP Обычное TCP-рукопожатие на `:443` Получен `RST` → чёрное дырообразование на IP-уровне. Редко — большинство провайдеров не заморачиваются.
TLS TLS-рукопожатие с SNI = целевой хост Сброс/таймаут именно здесь при работающем TCP — классическая «подпись» ТСПУ/DPI: промежуточный узел видит SNI и обрывает соединение.
HTTP `GET` после завершения рукопожатия 451 или подстановочная страница оператора, возвращающая 200 с телом «заблокировано Роскомнадзором».

Стоит выделить два зонда:

Вердикты и уверенность

Каждый результат содержит как вердикт, так и уровень уверенности. Вердикт говорит, какой именно сбой произошёл; уверенность — насколько можно доверять диагнозу.

Вердикт Значение
`OK` Сайт загрузился нормально.
`DNS_BLOCK` Системный DNS не резолвит, а DoH резолвит — соответствует отравлению DNS.
`TCP_RESET` На TCP-рукопожатие получен RST.
`TLS_BLOCK` TCP успешен, но TLS-рукопожатие сброшено, оборвано или иным образом убито (типичный DPI по SNI).
`HTTP_STUB` Ответом была известная подстановочная страница оператора или HTTP 451.
`TIMEOUT` Произошёл таймаут, недостаточно данных для дальнейшей классификации.
`DOWN` И резолвинг, и связность не работают, но не в форме, похожей на цензуру.
`UNKNOWN` Неожиданная ошибка, см. примечания.

Уровни уверенности:

Итоговая строка внизу отражает это. Если большинство сбоев в чёрном списке соответствует шаблонам с высокой уверенностью, будет сказано «Вероятно, нахождение в зоне блокировки РКН (высокая уверенность)». Если большинство сигналов средней уверенности — формулировка становится осторожнее. А когда сам белый список в основном не работает, инструмент не делает никаких выводов — без работающего базового уровня нельзя отличить цензуру от проблем с каналом, поэтому сводка становится «Неопределённо».

Конфиденциальность и модель угроз

`rkn-check` — это диагностический инструмент, а не инструмент обхода. Но люди, которые его запускают, как правило, уже находятся под сетевым наблюдением, поэтому настройки по умолчанию выбраны так, чтобы минимизировать след, оставляемый одним запуском.

JSON-вывод

`–json` выдаёт один объект, содержащий `self_info` (блок IP/ISP из заголовка или `null`, если установлен `–no-self-info`) и списки результатов. Каждый результат содержит полную трассировку зонда для каждой цели — какие DNS-резолверы что вернули, успешность TCP и TLS с таймингами, HTTP-статус, вердикт, уровень уверенности и человекочитаемые примечания.

(Сокращённый пример, полная версия в исходном репозитории)

{
  "self_info": {
    "ip": "95.165.xxx.xxx",
    "city": "Moscow",
    "country": "RU",
    "org": "AS12389 Rostelecom"
  },
  "whitelist": [
    {
      "name": "gosuslugi",
      "url": "https://www.gosuslugi.ru/",
      "verdict": "OK",
      "confidence": "HIGH",
      "notes": [],
      "sys_ip": "95.181.182.36",
      "doh_ip": "95.181.182.36",
      "sys_ips": ["95.181.182.36"],
      "doh_ips": ["95.181.182.36"],
      "dns_mismatch": false,
      "tcp_ok": true,  "tcp_time_ms": 18.4,
      "tls_ok": true,  "tls_time_ms": 42.1,
      "tls_cert_cn": "*.gosuslugi.ru",
      "status_code": 200, "plt_ms": 380.7
    }
  ],
  "blacklist": [
    {
      "name": "instagram",
      "url": "https://www.instagram.com/",
      "verdict": "TLS_BLOCK",
      "confidence": "MEDIUM",
      "notes": ["TLS reset right after ClientHello - consistent with SNI-based DPI filtering"],
      "tcp_ok": true,  "tcp_time_ms": 22.4,
      "tls_ok": false, "tls_error": "connection reset during TLS"
    }
  ]
}

`sys_ip` / `doh_ip` содержат наименьший отсортированный адрес из каждого набора для обратной совместимости; `sys_ips` / `doh_ips` содержат полные отсортированные списки. Поля трассировки зонда всегда присутствуют, чтобы можно было понять, почему был вынесен тот или иной вердикт — `TLS_BLOCK` с `tcp_ok: true` — это признак DPI по SNI; если `tcp_ok: false`, значит, что-то другое сломалось раньше.

Пользовательские списки целей

`–white-file` и `–black-file` принимают либо JSON, либо обычный текст. Формат определяется расширением файла (`.json` → JSON, всё остальное → текст).

JSON-формат — плоский объект, отображающий имя в URL:

{
  "google":   "https://google.com",
  "github":   "https://github.com",
  "rutracker": "https://rutracker.org"
}

Текстовый формат — одна запись на строку. Принимаются три формы:

# простой URL - имя автоматически извлекается из имени хоста
https://example.com

# имя<пробел>URL
github https://github.com

# имя=URL
custom=https://example.org

# пустые строки и строки, начинающиеся с #, пропускаются

К URL без схемы добавляется https://. Повторяющиеся имена перезаписываются (с логированием предупреждения); используйте уникальные имена, если нужно зондировать оба.

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

Установка

Требуется Python 3.10+.

Из PyPI:

pip install rkn-block-checker

Из исходников:

git clone https://github.com/MayersScott/rkn-block-checker.git
cd rkn-block-checker
pip install -e .

Для разработки (добавляет pytest и другое):

pip install -e ".[dev]"

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

rkn_checker/
  __main__.py     # python -m rkn_checker
  cli.py          # argparse + точка входа
  core.py         # оркестрация DNS -> TCP -> TLS -> HTTP
  dns.py          # системный резолвер + Cloudflare DoH (полные наборы адресов)
  network.py      # сырые TCP и TLS зонды
  http.py         # HTTP GET, набор заголовков, обнаружение подстановочных страниц
  output.py       # цветной CLI-отчёт
  lists.py        # парсер пользовательских файлов целей
  targets.py      # встроенные белый список, чёрный список, маркеры подстановок
  models.py       # CheckResult, Verdict, Confidence
tests/            # pytest, все сетевые вызовы замоканы

Тесты

pip install -e ".[dev]"
pytest

В тестовом наборе нет сетевых вызовов — каждый зонд замокан, поэтому тесты работают одинаково в CI, в самолёте или за корпоративным прокси.

Релизы

Релизы автоматически публикуются в PyPI через workflow `release.yml` при пуше тега `v*`. Workflow использует PyPI Trusted Publishing — ключ API не хранится в секретах репозитория.

Чтобы выпустить новую версию:

# сначала обновить версию в pyproject.toml, закоммитить
git tag v0.3.4
git push origin v0.3.4

Workflow проверяет, что тег соответствует версии в `pyproject.toml`, собирает sdist + wheel, запускает `twine check –strict`, публикует в PyPI и прикрепляет артефакты к GitHub Release с автоматически сгенерированными примечаниями.

Ограничения

Благодарности

Проект был значительно улучшен людьми, которые критически посмотрели на код и сообщили о проблемах с конкретными воспроизведениями. (Список участников с краткими описаниями их вклада сохранён в соответствии с оригиналом, но имена и ссылки на pull requests/issues были оставлены как есть, так как это часть истории проекта.)

Лицензия

MIT


Antistatus 12.05.2026 12:39