DNS через VPN работает, но имена .local всё равно не разрешаются: кто их резолвит?
Имя .local может полностью обойти резолвер VPN. Сравните три пути резолвера, а затем объявите домен вместо перестановки nsswitch.
Две машины в одной VPN, одно и то же имя хоста, и разрешается оно только на одной: разница обычно не в туннеле, а в том, какой резолвер ответил. На рабочем столе Linux это имя может пройти через переключатель служб имён, через stub systemd-resolved или через резолвер, который приложение принесло с собой, и каждый из них применяет своё правило к одному и тому же суффиксу. Именно на суффиксе правила расходятся, потому что .local не является нейтральной меткой. Выясните, какой путь на самом деле проходит сбойная программа, прежде чем менять порядок, в котором что-либо запускается.
Два резолвера, два разных ответа
Традиционный поиск glibc идёт по строке hosts: в nsswitch.conf и опрашивает каждый модуль по очереди, пока один не ответит. Клиент, который общается с systemd-resolved через stub-слушатель, вместо этого спрашивает один процесс, и этот процесс применяет политику для каждого подключения плюс свои особые случаи. Приложение, которое приносит свой резолвер или линкует библиотеку, делающую это, может обойти оба. Поэтому у одного имени хоста может быть три владельца на одной машине, и только один из них знает, что имел в виду VPN.
Определите владельца, прежде чем что-то менять, потому что исправление для каждого из трёх разное. Браузер и инструмент командной строки на одном рабочем столе могут законно расходиться, и это расхождение — подсказка, а не ошибка. Если браузер разрешает имя, а инструмент нет, вы отлаживаете путь резолвера, а не маршрут VPN. Подтвердите маршрут отдельно, чтобы сбой маршрутизации не был принят за сбой службы имён. Если оба согласны, сбой находится выше хоста, и здешняя конфигурация резолвера не стоит ещё одной правки.
Какая команда действительно спросила ваш резолвер
Две команды только для чтения отвечают на связанные вопросы, и их сравнение локализует проблему быстрее, чем чтение конфигурации. Используйте настоящее внутреннее имя и держите вывод приватным, потому что внутренние записи остаются внутренними. Запустите обе в той же сессии, в которой работает сбойная программа:
getent ahosts files.corp.local
resolvectl query files.corp.local
resolvectl statusПервая спрашивает через настроенные модули, что и испытывает типичная программа. Вторая спрашивает напрямую systemd-resolved и сообщает о подключении, протоколе и сервере, который ответил. Запрос к корпоративному серверу по адресу доказывает лишь то, что сервер хранит запись, потому что он ничего не говорит о том, спрашивало ли его когда-нибудь приложение. Прочитайте подключение, которое несёт VPN, и домены, которые оно заявляет, а затем сравните этот список с суффиксом в сбойном имени.
Почему .local обходит вашу зону unicast
справка systemd-resolved сообщает, что многосоставные имена, оканчивающиеся на .local, при включённом mDNS обычно уходят в multicast DNS, а не в обычный unicast DNS. RFC 6762 резервирует это пространство имён для link-local multicast, поэтому у корпоративной зоны может быть правильная запись, о которой для этого суффикса никогда не спрашивают. Туннель может идеально маршрутизировать резолвер и всё равно проиграть гонку. Успешный ping из кэша ничего не говорит о поиске, который только что произошёл.
Есть документированное исключение, и оно решает большинство таких случаев: когда подключение объявляет этот суффикс как домен поиска или домен маршрутизации, демон держит его на пути unicast и пропускает особый случай multicast. Это политика для каждого подключения, а не глобальное предпочтение. Две машины с одним и тем же сервером VPN могут вести себя по-разному, когда один сетевой профиль объявляет домен, а другой нет, поэтому читайте активный профиль, а не тот, который, как вам кажется, вы редактировали.
Узкое исключение побеждает глобальную перестановку
Для существующей зоны, которую вы не можете переименовать, попросите владельцев резолвера и VPN объявить домен на том подключении, которое его несёт. Запись домена маршрутизации для этого одного суффикса плюс нужный адрес сервера — небольшое изменение с названным владельцем, и она живёт вместе с подключением, а не в файле, отредактированном вручную.
Оно переживает и отключение, потому что политика подключения применяется заново, когда подключение возвращается. Правка общего nsswitch.conf — соблазнительная и более дорогая альтернатива, потому что она меняет поведение поиска для каждого имени на машине, включая локальное обнаружение. Отключение демона multicast тоже не эквивалентно: оно убирает локальное поведение, не обучая ни один резолвер корпоративной зоне. Если служба новая, а не унаследованная, поместите её в поддомен, который контролирует ваша организация, и полностью пропустите конкуренцию. Выбирайте узкое исключение, когда имя зафиксировано в прошивке или напечатано на этикетке, и новый поддомен, когда вы всё ещё контролируете клиента.
Что доказать после изменения
Докажите исправление собственным поиском приложения, а не инструментом, который вы поставили для тестирования, и очистите любой кэш, который мог бы ответить вместо него. Затем подтвердите путь резолвера и подключение, которое дало ответ. Наконец проверьте, что локальное обнаружение ведёт себя как до изменения, потому что принтер, который перестаёт появляться, — это та часть, которую люди замечают последней. Эти три команды проверяют имя, путь и идентичность TLS именно в этом порядке:
getent ahosts files.corp.local
resolvectl query files.corp.local
curl -sv --max-time 5 https://files.corp.local/ 2>&1 | head -n 20Правильный адрес с неправильным сертификатом всё равно проваливает строгого клиента, поэтому проверьте имя, которое ожидает приложение, когда разрешение заработает. Подтвердите, что служба принимает подключения с адреса VPN, а не только из офисного диапазона. Запишите охват домена, сервер и владельца в документацию подключения. Иначе следующий человек, столкнувшийся с этим сбоем, потянется к той же глобальной правке, которую вы только что избежали.