VPN подключается, и три несвязанных инструмента отказывают тремя разными способами в тот же день. mitmproxy перестаёт видеть запросы, Chrome отказывает отладчику, а Gradle выбрасывает BindException при привязке локального сокета. Общее подозрение — туннель блокирует localhost. Он не может: 127.0.0.1 обрабатывается внутри ядра и никогда не доходит до адаптера, не говоря уже о шлюзе.

Три уровня, три разных поломки

С клиентом изменился не маршрут к loopback. Это локальный прокси, хранилище доверия машины и пакетный фильтр, и каждый из них ломает свою часть рабочего процесса разработчика. Отнести симптом к правильной строке — большая часть диагностики:

SymptomLayerFirst check
Proxy sees no trafficLocal proxy or listenerss -lntp, or netstat -ano on Windows
TLS error in one tool onlyTrust storeWhich CA bundle does that runtime read?
Local bind or connect refusedPacket filter or port ownerWho holds the port, and what rule drops it?

Почти каждый отчёт такого рода начинается с последней строки и идёт вверх, что неверно. Туннель — единственный уровень, который доказуемо не видит трафик loopback, поэтому заслуживает меньше всего подозрений. Начните с того, что привязал процесс, затем спросите, каким сертификатам он доверяет, и только потом смотрите на политику на машине.

Начните со слушателя, а не с туннеля

Когда прокси на 127.0.0.1:8080 перестаёт получать трафик, произошло одно из трёх: он не запустился, привязал другой порт, или фильтр сбросил соединение loopback. Перечисление слушающих сокетов отвечает на это одной командой и показывает, какой процесс владеет портом, когда два инструмента расходятся в том, кто был первым.

Локальный адрес в поиске маршрута подтверждает то же самое с другой стороны. ip route get к цели loopback сообщает устройство loopback, никогда не туннель, и это полезная фраза наготове, когда кто-то предлагает изменение маршрутизации как решение.

Уровень прокси: окружение — это не конфигурация

Многие корпоративные клиенты запускают HTTP-прокси и ожидают, что приложения будут им пользоваться. Установка HTTPS_PROXY в оболочке исправляет инструменты командной строки, которые его уважают, и ничего не делает для инструмента, читающего свой собственный файл настроек. Gradle, Selenium и gRPC каждый обращается к своей конфигурации, а прокси, экспортированный в одном терминале, невидим для демона, запущенного IDE.

Инструменты контейнеров — обычное место, где это становится заметным. Loopback контейнера — его собственный, поэтому 127.0.0.1 внутри контейнера никогда не означает прокси хоста; нужен адрес хоста или настройка сети хоста. Исправление, которое работает в оболочке и падает при сборке, обычно и есть эта строка, а не туннель.

Уровень доверия: инструмент читает другое хранилище

Перехват — второе изменение, и он даёт самые обманчивые ошибки. Клиент предъявляет собственный сертификат для проверяемых соединений, поэтому браузер, доверяющий корпоративному корню, успешно работает, а инструмент со встроенным хранилищем CA отказывает. requests Python через certifi — классический случай: хранилище операционной системы может быть правильным, и запрос всё равно падает, потому что эта среда выполнения его никогда не читает. В тексте ошибки перехват упоминается редко, поэтому эту строку ошибочно диагностируют как сломанную конечную точку.

Сравните, что конечная точка на самом деле предъявляет, с тем, что инструмент проверил. openssl s_client показывает цепочку, отправленную сервером; собственный вывод проверки инструмента показывает, что он решил. Когда они расходятся, REQUESTS_CA_BUNDLE или SSL_CERT_FILE является рычагом для этой среды выполнения, и корпоративный корень должен находиться в хранилище, которое читает эта среда, а не в глобальном месте, которое уважают лишь некоторые инструменты.

Изменение версии, исправляющее ошибку SSL, — это свидетельство о политике доверия и шифров, а не о VPN. Понижение версии Python, после которого заработал клиент SOAP, изменило встроенное хранилище CA и настройки TLS по умолчанию; сетевой путь не сдвинулся.

Уровень фильтра: он тоже может сбросить loopback

Третье изменение — пакетный фильтр, и некоторые продукты устанавливают правила, сбрасывающие трафик, который не попадает в туннель. Локальные слушатели могут попасть под них. Это превращает рабочий сокет в отклонённое или просроченное соединение, и получившаяся ошибка выглядит как дефект приложения, а не как политика машины.

Владение портом — вторая половина этого уровня. BindException означает, что сокет не удалось открыть, а это иной отказ, чем отклонённое соединение. Проверьте, не держит ли порт уже другой процесс, прежде чем винить фильтр, затем поищите правило, сбрасывающее локальный трафик, и добавьте самое узкое разрешение, которое поддерживает продукт. Два инструмента, конкурирующие за один и тот же отладочный порт, дают ровно то же сообщение, что и блокировка политикой, и только один из них исправляется изменением брандмауэра.

Отладочный порт Chrome падает в том же семействе. Браузер запускается, драйвер не достигает конечной точки DevTools, и в сообщении называется DevTools, а не сеть. Дополнительные флаги запуска и лишний менеджер драйверов меняют то, какой процесс владеет портом, поэтому их удаление иногда выглядит как исправление VPN.

Исправьте уровень, который отказал

Исправьте уровень, который отказал, а не туннель. Недоступному слушателю loopback нужно исправить слушатель или порт. Недоверенному сертификату нужен корпоративный корень, установленный там, где смотрит именно эта среда выполнения, с узким исключением. Фильтру, сбрасывающему локальный трафик, нужно конкретное правило разрешения, а не отключённый фильтр, потому что отключение снова открывает и всё остальное, что он защищал.

Переподключение VPN не проверяет ни один из этих уровней. Оно лишь повторно выполняет изменение, которое их сломало, поэтому те же три отказа возвращаются после каждого переподключения и исчезают после каждой перезагрузки, оставляющей клиент неактивным.

Похожие статьи