scutil --dns печатает конфигурацию резолвера, к которой macOS действительно обращается, а не тот единственный DNS-сервер, который вы ввели в панели настроек. Вывод длиннее, чем ожидает большинство, потому что система держит отдельные блоки резолвера для стандартного пути, для интерфейсов с областью действия и для перенаправления, специфичного для домена. Блок в начале вывода не обязательно тот, который отвечает на запрос. Если частное имя разрешается в офисе и перестаёт работать в момент подключения VPN, несоответствие в правилах сопоставления и маршрутах, а не в адресе сервера. Сначала прочитайте порядок, затем докажите ответ реальным запросом.

Сначала порядок блоков, потом адреса

Каждая запись открывается resolver #N и перечисляет nameserver[0], иногда if_index, строку flags, reach, а когда блок не является простым значением по умолчанию, ещё domain и список search domain. Резолвер номер 1 без домена — это значение по умолчанию, обслуживающее публичные имена. Всё, что несёт Scoped в своих флагах, привязано к интерфейсу, названному в if_index, а всё помеченное Supplemental действует только для доменов, перечисленных под ним.

Выбор — это сопоставление суффикса. Для имени вроде intranet.corp.example macOS предпочитает резолвер, запись domain которого является самым длинным совпадающим суффиксом, поэтому блок с domain : corp.example побеждает значение по умолчанию, даже если стоит далеко внизу вывода. order разрешает равенство между доменами одинаковой длины. Первому взгляду редко нужно больше: весь вывод, когда вы хотите прочитать один блок от начала до конца, начальные строки, чтобы узнать порядок блоков, и фильтрованный проход, печатающий заголовки блоков рядом со строками полей. Блоки с областью действия появляются под своим заголовком и читаются как продолжение списка выше, поэтому держите заголовок в поле зрения, когда цитируете вывод.

scutil --dns
scutil --dns | sed -n '1,45p'
scutil --dns | grep -nE '^resolver #|^DNS configuration'
scutil --dns | grep -nE 'resolver #[0-9]+|if_index|domain|flags|nameserver'

Сопоставьте if_index с интерфейсом туннеля

Индекс полезен, только если вы можете назвать интерфейс за ним. scutil --nwi перечисляет сетевые сведения, которые хранит система, включая основной интерфейс и доступность, а ifconfig -l даёт имена, где utun0 по utun9 — кандидаты в туннели, которые клиент обычно создаёт. Apple использует scutil --dns как собственный пример проверки в руководстве по развёртыванию, и описывает, как Network Extension может направлять выбранные домены к выбранным резолверам, — именно этот механизм и раскрывают те блоки с областью действия.

Проверка, решающая вопрос, — находится ли резолвер на пути, который установил туннель:

scutil --nwi
ifconfig utun4
route -n get 10.20.0.53
netstat -rn | grep -m5 utun

Если route -n get возвращает шлюз и интерфейс, не совпадающие с записью резолвера, адрес может быть совершенно правильным и всё равно недостижимым. Разделённый туннель, несущий только корпоративные подсети, отбрасывает запросы к DNS-серверу за их пределами, и сбой проявляется как тайм-аут, поэтому вывод конфигурации продолжает выглядеть чистым.

Сначала спросите системный резолвер, затем сервер

Три инструмента отвечают на три разных вопроса, и их смешение порождает большинство неверных выводов в этой области. dscacheutil -q host -a name проходит через тот же системный резолвер, который используют обычные приложения, поэтому блоки с областью действия и дополнительные действуют. dig без аргумента сервера читает /etc/resolv.conf, что не является источником истины для разрешения с областью действия на macOS, и полностью пропускает правила для отдельных доменов. dig @address достигает ровно одного сервера и ничего не говорит о выборе.

dscacheutil -q host -a name intranet.corp.example
dig intranet.corp.example
dig @10.20.0.53 intranet.corp.example
nslookup intranet.corp.example

Когда первая команда отвечает, а вторая возвращает NXDOMAIN, вы нашли искомое разделение и ничего не сломано. Когда первая завершается тайм-аутом, а dig @10.20.0.53 отвечает, резолвер работает, но недостижим на пути, выбранном туннелем, поэтому следующий шаг — route -n get, а не изменение настроек DNS. Держите частные имена вне всего, что вы вставляете в тикет или общую заметку.

Чего вывод не может вам показать

Несколько слоёв сидят над списком резолверов или рядом с ним, и каждый может отправить запрос туда, о чём вывод никогда не упоминает. Браузер с включённым безопасным DNS может разрешать через собственный шифрованный канал, поэтому страница, которая загружается, пока dscacheutil уходит в тайм-аут, — не противоречие. DNS-прокси, установленный защитным ПО, работает как провайдер Network Extension и сам пересылает запросы, а scutil --dns показывает то, что настроено, а не вышестоящий адрес, которым прокси в итоге воспользовался. Домены поиска добавляют третий изгиб: к неквалифицированному имени по очереди дописывается каждый перечисленный суффикс, поэтому ответивший блок может быть таким, о котором вы никогда не подозревали.

Устаревшие ответы проще всего исключить и чаще всего пропускают:

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
scutil --dns | head -20

Если после очистки вывод меняется, состояние было в кэше и прежний вывод описывал туннель, которого уже не было. Если он не меняется, конфигурация такова, какова она есть, и вопрос переходит к маршрутам и к политике приложений.

Короткое руководство для «до» и «после»

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

scutil --dns > ~/dns-before.txt
# connect the VPN, then:
scutil --dns > ~/dns-after.txt
diff -u ~/dns-before.txt ~/dns-after.txt
dscacheutil -q host -a name intranet.corp.example

Читайте разницу по блокам, а не по строкам. Ожидаемая форма — новый блок с областью действия, несущий индекс интерфейса туннеля и запись domain для частного суффикса. Новый резолвер по умолчанию, указывающий на публичный адрес, — находка, которую стоит поднять перед владельцем клиентского профиля. Затем повторите поиск внутри приложения, которое действительно сломалось, а не только в оболочке, и запишите интерфейс из route -n get рядом с результатом.

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

Четыре проверки в таком порядке: совпадает ли какой-либо блок резолвера с самым длинным суффиксом имени; привязан ли этот блок к интерфейсу, который установил туннель; использует ли маршрут к его серверу имён туннель; и возвращает ли ответ системный резолвер, а не dig. Первая неудачная проверка подсказывает, менять ли политику DNS, маршруты туннеля или приложение. Если все четыре проходят, а имя всё ещё не разрешается, проблема выше DNS, и следующее, что нужно осмотреть, — всё, что отвечает на порт 53 перед ним.

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