Послойная диагностика DNS, TCP/IP, TLS/SNI, HTTP Host, QUIC и маршрутов — с доказательными выводами вместо гадания по одному timeout.
netprobe — stdlib-only Python-инструмент для послойной диагностики сетевой
доступности и вероятной фильтрации. Он идёт по цепочке:
flowchart LR
A["DNS<br/>system · UDP · TCP · DoH"] --> B["Pinned IP<br/>TCP · IPv4 · IPv6"]
B --> C["TLS / SNI<br/>normal · fragmented · no-SNI"]
C --> D["HTTP Host<br/>normal · fragmented"]
B --> E["QUIC<br/>UDP/443"]
B --> F["Traceroute"]
C --> G["Direct ↔ VPN<br/>exact endpoint comparison"]
Главный принцип: один timeout, RST, другой CDN-IP или * в traceroute не
называются «DPI». Инструмент сохраняет сырые факты в JSON, делает осторожные
выводы inconclusive/suspected, а высокую уверенность получает из
дифференциальных проверок на одном endpoint:
- обычный TLS ClientHello против того же ClientHello с SNI, разделённым между TCP-сегментами;
- обычный HTTP Host против разделённого между TCP-сегментами;
- прямой путь против VPN на том же exact
IP:portи варианте пробы.
- системный DNS, прямой DNS/UDP, DNS/TCP и два DNS-over-HTTPS;
- NXDOMAIN/SERVFAIL/REFUSED, разные ответы, special-use/private ответы;
- IPv4 и IPv6 отдельно;
- TCP 80/443 и порт из URL, включая timeout/refused/reset/unreachable;
- TLS с целевым SNI, фрагментированным SNI, без SNI, TLS 1.2, TLS 1.3;
- стандартная проверка цепочки и hostname сертификата;
- HTTP по фиксированному IP с правильным Host, без follow-redirect;
- явные fingerprints поддерживаемых страниц блокировки и HTTP 451;
- QUIC Version Negotiation по UDP/443 без сторонних библиотек;
- системный
tracert/tracerouteс локализационно-независимым парсером; - точные VPN-кандидаты
/32и/128и безопасный managed route-файл; - сравнение
direct/vpnотчётов только на совпавших endpoint.
Требуется Python 3.11+; runtime-зависимостей нет.
uv sync --extra dev
uv run netprobe doctorБез установки тоже можно:
$env:PYTHONPATH = "src"
python -m netprobe doctorПолная диагностика с человекочитаемым итогом и JSON-артефактом:
uv run netprobe diagnose https://example.com `
--json-out artifacts/example-direct.json `
--path-label directКороткий запуск без traceroute:
uv run netprobe diagnose example.com --quick --no-traceJSON для ИИ-агента — единственный документ в stdout, прогресс идёт в stderr:
uv run netprobe diagnose example.com --json > report.jsonТрассировка. Сначала имя резолвится, затем tracert получает только проверенный
числовой IP одним argv-элементом; shell не используется:
uv run netprobe trace example.com --family both --jsonСначала без VPN:
uv run netprobe diagnose blocked.example `
--no-trace --path-label direct `
--json-out artifacts/blocked-direct.jsonЗатем включить VPN и повторить. Важно, чтобы в отчётах были одинаковые IP:
uv run netprobe diagnose blocked.example `
--no-trace --path-label vpn `
--json-out artifacts/blocked-vpn.json
uv run netprobe compare `
artifacts/blocked-direct.json `
artifacts/blocked-vpn.jsonЕсли VPN меняет DNS и выбирает другой CDN-IP, compare не выдаст ложный
дифференциальный вывод: разные endpoints будут помечены как несопоставимые.
Показать, какие конечные адреса сейчас рекомендуются:
uv run netprobe routes suggest example.com --jsonДобавить/обновить адреса в файле:
uv run netprobe routes sync example.com --file vpn-routes.txt --jsonПри первом изменении рядом появится vpn-routes.txt.netprobe.json. Sidecar
хранит ownership: sync удаляет только устаревшие строки, ранее добавленные
самим netprobe, и никогда не присваивает уже существующую ручную строку.
Операции идемпотентны и записываются через временный файл + fsync +
os.replace; symlink отклоняется.
Удалить записи одной цели или проверить файл:
uv run netprobe routes remove example.com --file vpn-routes.txt
uv run netprobe routes validate --file vpn-routes.txt --jsonДобавляются только конечные A/AAAA адреса сервиса:
- IPv4 —
/32; - IPv6 —
/128.
Промежуточные IP из traceroute добавлять нельзя: это роутеры провайдера и транзита, а не адреса сайта. Нельзя автоматически расширять адрес до ASN/BGP префикса: CDN и хостинг делят подсети между множеством чужих сервисов.
Статический файл не означает «навсегда» для CDN. IP меняются, поэтому запускайте
routes sync по расписанию или перед использованием. Если браузер уходит на
другой hostname, API или CDN, диагностируйте его отдельной целью. Если есть
AAAA, добавьте /128 и убедитесь, что VPN маршрутизирует IPv6, иначе приложение
может обойти IPv4 /32.
0— команда выполнена и отчёт сформирован;1— только--fail-on-suspectedлибо ошибкиroutes validate;2— неверная цель/аргументы/route-файл;3— локальная ошибка инструмента;130— прерывание пользователем.
Сетевой timeout является данными отчёта, а не аварией CLI.
- Абсолютно все виды фильтрации одним клиентом определить невозможно.
- Без второго запуска через VPN вывод об IP/SNI/HTTP-фильтрации обычно остаётся подозрением.
- QUIC-timeout не доказывает блокировку: endpoint может не поддерживать QUIC или молча игнорировать Version Negotiation.
- Traceroute обычно использует ICMP/UDP системной утилиты; ICMP может фильтроваться при полностью рабочем HTTPS.
- HTTPS Host зашифрован внутри TLS. Проверка фрагментации Host относится к открытому HTTP; для HTTPS отдельно анализируются SNI и сертификат.
- ECH скрывает SNI там, где поддерживается клиентом и сервером; stdlib Python не даёт управляемого ECH-теста.
- Корпоративный proxy, антивирус, неверное время и split-horizon DNS могут выглядеть как вмешательство — они перечисляются как альтернативы.
python -m pytest -q
ruff check --fix src tests
ruff format src tests
pyright src testsUnit-тесты не используют живую сеть. Реальный smoke-run выполняется отдельно.