WSL2 не наследует корпоративный VPN, и именно в этом ошибка
WSL2 работает в собственной виртуальной сети и никогда не наследует VPN-стек хоста. Разделите сбои имён и сбои пути ещё до того, как трогать resolv.conf.
Внутренняя вики открывается в Edge, а git clone внутри дистрибутива завершается по тайм-ауту. Это единственное наблюдение обычно читают как «VPN блокирует WSL2», и следующий час уходит на правку /etc/resolv.conf. Более полезное чтение: у WSL2 изначально не было сетевого пути хоста — он работает во вспомогательной ВМ с собственным адаптером, собственными маршрутами и файлом resolver, который Windows создаёт для него. Всё дальнейшее зависит от того, чего из этих трёх вам действительно не хватает.
У ВМ свой стек, свои метрики и свой resolver
В стандартном режиме NAT дистрибутив стоит за виртуальным коммутатором и выходит в интернет через хост, но не видит его адаптеры. ip addr показывает один интерфейс с приватным адресом, ip route показывает маршрут по умолчанию через этот коммутатор, а /etc/resolv.conf — сгенерированный файл, указывающий на stub resolver, который выбрал Windows. Ничего из этого не меняется оттого, что на стороне Windows запустился VPN-клиент.
Поэтому «браузер работает» доказывает так мало. Браузер использует стек хоста, туннель и resolver-политику хоста. Ваша оболочка использует другой стек, который случайно делит физическую сетевую карту. Они совпадают в благоприятном случае и расходятся ровно тогда, когда VPN ставит фильтр, переписывает список DNS или добавляет маршрут к подсети виртуального коммутатора.
Два теста решают, в каком мире вы находитесь, и они должны выполняться внутри дистрибутива:
getent hosts example.com
curl -sS -m 8 -o /dev/null -w "%{http_code}\n" 1.1.1.1
ip route
cat /etc/resolv.conf
Если имена не разрешаются, а буквальный адрес отвечает, это проблема resolver. Если имена и адреса падают вместе, это проблема пути, и никакая правка resolver её не затронет. Дальше идут доказательства со стороны Windows: Get-NetAdapter | Get-DnsClientServerAddress и route print -4 показывают, занял ли туннель подсеть, в которой живёт ваша ВМ.
Миф первый: корпоративные DNS-серверы это исправляют
Правка файла resolver — классический совет, и он верен примерно в половине случаев. Когда он верен, причина конкретна: сгенерированный файл указывает на resolver, который знает только публичные имена, поэтому запрос intranet.example.internal возвращается как несуществующий, хотя путь в порядке.
Закрепить серверы VPN означает остановить повторную генерацию файла Windows, потому что любой файл, написанный вручную, заменяется при следующем запуске:
[network]
generateResolvConf = false
Сохраните это как /etc/wsl.conf, выполните wsl --shutdown из Windows, затем запустите дистрибутив и запишите /etc/resolv.conf с серверами туннеля первыми и публичным resolver только как запасной. Это долговременное изменение с ценой обслуживания: файл больше не следует за хостом, поэтому когда корпоративные адреса DNS меняются, дистрибутив продолжает спрашивать старые. Кто-то должен владеть этим файлом.
Он также ничего не делает, когда сбой шире. Если curl к 1.1.1.1 завершается по тайм-ауту, клиент туннеля фильтрует виртуальный коммутатор или направляет подсеть ВМ в туннель, и правильный resolver даёт только имена, до которых всё ещё нельзя добраться.
Миф второй: изменение метрики держится
Когда имена разрешаются, но трафик уходит через физический адаптер, рычаг — метрики интерфейсов. Дайте адаптеру VPN высокую стоимость, а коммутатору WSL низкую:
Get-NetAdapter | Where-Object InterfaceDescription -Match "AnyConnect" | Set-NetIPInterface -InterfaceMetric 4000
Get-NetIPInterface -InterfaceAlias "vEthernet (WSL)" | Set-NetIPInterface -InterfaceMetric 1
Затем помните, что во многих сборках клиента адаптер туннеля пересоздаётся при каждом подключении, а метрика возвращается к значению по умолчанию. Разовая команда — это исправление, которое тихо истекает, обычно за выходные, и заявка возвращается с «на прошлой неделе работало». Запланированная задача, запускаемая событием VPN, или скрипт, который пользователь запускает после подключения, — честная версия этого исправления.
Тот же срок действует для маршрутов хоста, добавленных для одного упрямого префикса. Они ценны как диагностика, потому что говорят, в одном ли направлении проблема или во всём пути, но это не архитектура.
Миф третий: одно исправление покрывает каждую сборку Windows
| Approach | What it actually does |
|---|---|
| Resolver pin | Fixes private names only; no effect on path failures |
| Sidecar distribution | Forwards traffic over a socket to a helper VM, so the switch's filter no longer matters |
| Mirrored networking | Gives the distribution the host's interface set; also enables DNS tunnelling |
wsl-vpnkit — это шаблон sidecar: небольшая дистрибуция владеет путём на стороне хоста и пересылает за другие дистрибутивы через виртуальный сокет, поэтому трафик приложений перестаёт зависеть от отфильтрованного коммутатора. Нужен работающий стандартный путь, то есть удалить переопределения networkingMode и dnsTunneling из %UserProfile%\.wslconfig, восстановить generateResolvConf = true в каждой работающей дистрибуции и запускать службу при входе.
Зеркальный режим — встроенная альтернатива в Windows 11 22H2 и новее, и это одна настройка плюс выключение:
[wsl2]
networkingMode=mirrored
Внутри дистрибутива ip addr тогда перечисляет адаптеры хоста, туннель может появиться среди них, а DNS-туннелирование пересылает запросы через resolver Windows даже когда клиент переписывает список DNS. Это не универсально: некоторые драйверы фильтрации всё ещё отбрасывают зеркальный путь, а правилам брандмауэра Hyper-V может понадобиться явное разрешение. Руководство по сетям WSL от Microsoft — страница, которую нужно сверить со своей сборкой, прежде чем применять рецепт, написанный для более новой.
После каждого изменения проверяйте три вещи
Выберите один механизм на машину и запишите его, потому что два сочетаются плохо. Sidecar поверх зеркального режима удваивает пересылку, а зеркальный хост с устаревшей записью sidecar в .wslconfig обычно падает после обновления, а не до него.
Что бы вы ни выбрали, приёмочный тест — те же три запроса внутри дистрибутива: внутреннее имя, публичное имя и сырой адрес. Затем повторите их после отключения и повторного подключения туннеля и после wsl --shutdown. Если падает только внутреннее имя, это resolver-политика; если внутреннее и публичное имена падают вместе при работающем адресе, это всё ещё resolver-политика; если падает всё, это путь.
Если один внутренний хост падает, а остальные работают, перестаньте смотреть на resolver и поищите отсутствующий маршрут для этого префикса. Если всё работает до следующего переподключения, вы нашли исправление, зависящее от состояния времени выполнения, и его нужно применять повторно автоматически или заменить одним из двух механизмов выше.