Небольшой 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 ограниченных РКН), выдаёт отчёт по каждому сайту и сводное заключение.
rkn-check --url https://example.com rkn-check --url example.com --url google.com # повторить для нескольких
Полностью пропускает встроенные списки и выполняет ad-hoc проверку только переданных URL. Сводного заключения нет — не с чем сравнивать. Используйте, когда нужно узнать, «открылся ли этот конкретный сайт?», не тратя время на полное сканирование.
# имена всех заблокированных сайтов 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
См. раздел Пользовательские списки целей.
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` выдаёт один объект, содержащий `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 были оставлены как есть, так как это часть истории проекта.)