Использую censorcheck для диагностики сети в связке с Zapret2 (nfqws2) и локальным DoH (dnscrypt-proxy2). Инструмент хорошо справляется с проверкой доступности, но архитектурная зависимость от curl и nslookup (L7) делает невозможным отличить цензуру на уровне сети (DPI/L3) от ограничений сервера (WAF).
Это приводит к ложным срабатываниям и пропуску блокировок, которые выглядят как "сайт не отвечает", хотя на самом деле применяется DPI.
Эмпирические данные
ТСПУ используют разные механизмы блокировки, которые censorcheck интерпретирует одинаково:
| Домен |
Вывод censorcheck |
Реальный механизм |
Технические данные |
instagram.com |
Blocked by IP |
L3 IP-бан |
TCP SYN дропается (tcping: CLOSED) |
discord.com |
Blocked or site didn't respond |
L7 TCP-freeze |
TCP OPEN, TLS OK, но передача данных обрывается (0 байт за 5с) |
facebook.com |
Redirected (307) |
HTTP-инъекция DPI |
Редирект на домен-заглушку провайдера |
x.com |
Access Denied (403) |
WAF / Geo-block |
403 от Cloudflare, сайт не заблокирован провайдером |
Предложения по архитектуре
1. Разделять L3 IP-бан и L7 TCP-freeze
Функция is_port_open проверяет только SYN-ACK. При TCP-freeze порт открыт, но данные не идут.
Решение: Анализировать объем скачанных данных и тайминг. Если порт OPEN, TLS OK, но size_download == 0 при time_total >= timeout — это TCP-freeze (DPI drops large packets).
2. Детекция HTTP-инъекций (редиректы на заглушки)
Редирект 307 на домен провайдерской заглушки — это не обычный редирект.
Решение: Анализировать заголовок Location при 3xx. Если он содержит известные паттерны заглушек (например, tspu., block.), классифицировать как DPI Injection, а не Redirected.
3. Проблема с --retry-all-errors
Флаг --retry-all-errors в curl_opts (строка 252) заставляет ретраить HTTP-ошибки. При DPI-инъекции с 307, curl может уйти в ретрай или следовать редиректу (-L), загрузить страницу заглушки и выдать ложный статус доступности. Для диагностики цензуры ретраи HTTP-ошибок маскируют саму блокировку.
4. Классификация 403 от Cloudflare
403 от Cloudflare — это Bot Detection или Geo-block, а не DPI.
Решение: Анализировать заголовок Server: cloudflare. При коде 403 и наличии этого заголовка классифицировать как WAF/Geo-block (not DPI). Это снизит шум для пользователей, отлаживающих обход.
5. Детекция DNS Spoofing при локальном DoH
Текущая проверка check_dns_hijacking сравнивает системный DNS и DoH. Если система уже использует локальный DoH/DoT (dnscrypt-proxy2), оба запроса идут через один зашифрованный канал. Подмена на уровне провайдерского UDP не детектируется.
Решение: Для проверки спуфинга нужен прямой UDP-запрос в обход локального прокси (например, через /dev/udp/9.9.9.9/53), так как dig @9.9.9.9 может всё равно маршрутизироваться через локальный резолвер.
Предлагаемая модель реализации
Чтобы не ломать текущий UI, предлагаю вынести классификацию в опциональный флаг --classify или расширить JSON-вывод (-j) полем block_type:
l3_ip_ban (TCP CLOSED)
l7_tcp_freeze (Port OPEN, TLS OK, 0 bytes)
dpi_injection (307 to ISP stub)
waf_geo_block (403 Cloudflare)
Использую
censorcheckдля диагностики сети в связке с Zapret2 (nfqws2) и локальным DoH (dnscrypt-proxy2). Инструмент хорошо справляется с проверкой доступности, но архитектурная зависимость отcurlиnslookup(L7) делает невозможным отличить цензуру на уровне сети (DPI/L3) от ограничений сервера (WAF).Это приводит к ложным срабатываниям и пропуску блокировок, которые выглядят как "сайт не отвечает", хотя на самом деле применяется DPI.
Эмпирические данные
ТСПУ используют разные механизмы блокировки, которые
censorcheckинтерпретирует одинаково:instagram.comBlocked by IPtcping: CLOSED)discord.comBlocked or site didn't respondfacebook.comRedirected (307)x.comAccess Denied (403)Предложения по архитектуре
1. Разделять L3 IP-бан и L7 TCP-freeze
Функция
is_port_openпроверяет только SYN-ACK. При TCP-freeze порт открыт, но данные не идут.Решение: Анализировать объем скачанных данных и тайминг. Если порт OPEN, TLS OK, но
size_download == 0приtime_total >= timeout— этоTCP-freeze (DPI drops large packets).2. Детекция HTTP-инъекций (редиректы на заглушки)
Редирект 307 на домен провайдерской заглушки — это не обычный редирект.
Решение: Анализировать заголовок
Locationпри 3xx. Если он содержит известные паттерны заглушек (например,tspu.,block.), классифицировать какDPI Injection, а неRedirected.3. Проблема с
--retry-all-errorsФлаг
--retry-all-errorsвcurl_opts(строка 252) заставляет ретраить HTTP-ошибки. При DPI-инъекции с 307, curl может уйти в ретрай или следовать редиректу (-L), загрузить страницу заглушки и выдать ложный статус доступности. Для диагностики цензуры ретраи HTTP-ошибок маскируют саму блокировку.4. Классификация 403 от Cloudflare
403 от Cloudflare — это Bot Detection или Geo-block, а не DPI.
Решение: Анализировать заголовок
Server: cloudflare. При коде 403 и наличии этого заголовка классифицировать какWAF/Geo-block (not DPI). Это снизит шум для пользователей, отлаживающих обход.5. Детекция DNS Spoofing при локальном DoH
Текущая проверка
check_dns_hijackingсравнивает системный DNS и DoH. Если система уже использует локальный DoH/DoT (dnscrypt-proxy2), оба запроса идут через один зашифрованный канал. Подмена на уровне провайдерского UDP не детектируется.Решение: Для проверки спуфинга нужен прямой UDP-запрос в обход локального прокси (например, через
/dev/udp/9.9.9.9/53), так какdig @9.9.9.9может всё равно маршрутизироваться через локальный резолвер.Предлагаемая модель реализации
Чтобы не ломать текущий UI, предлагаю вынести классификацию в опциональный флаг
--classifyили расширить JSON-вывод (-j) полемblock_type:l3_ip_ban(TCP CLOSED)l7_tcp_freeze(Port OPEN, TLS OK, 0 bytes)dpi_injection(307 to ISP stub)waf_geo_block(403 Cloudflare)