Як перевірити DNS-резолвери, які ваш Mac використовує у VPN
scutil --dns друкує стан резолвера, який macOS справді побудував. Зіставте кожен блок з інтерфейсом, запитайте справжнє ім’я і доведіть, який сервер відповів.
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 перед ним.