Mengapa nama host internal beresolusi di dig tetapi gagal di curl pada VPN
dig menjawab, tetapi curl melaporkan tidak dapat menyelesaikan host. Bandingkan kedua rantai pencarian, lalu perbaiki nsswitch, DNS per tautan, atau sufiks pencarian yang salah.
Laptop Anda berada di VPN, dig service.internal.example menjawab dengan alamat 10.x, dan curl tetap keluar dengan Could not resolve host. Tunnel bukan masalahnya: ia membawa kueri dig tanpa keluhan. Yang berbeda adalah siapa yang bertanya. dig mengirim satu kueri ke satu server yang Anda sebutkan, sedangkan curl melewati rantai pencarian sistem operasi, dan rantai itu punya aturan sendiri tentang server mana yang ditanya.
Dua pencarian untuk nama yang sama
dig adalah stub resolver tersendiri. Ia membaca /etc/resolv.conf, memilih server nama, mengirim satu kueri A atau AAAA, dan mencetak jawabannya. Ia melewati nsswitch sepenuhnya dan tidak tahu apa pun tentang keadaan per tautan yang disimpan systemd-resolved atau NetworkManager di luar berkas itu, itulah sebabnya jawaban dig bisa benar tetapi tetap tidak memberi tahu apa yang akan dilihat aplikasi Anda.
Aplikasi memanggil getaddrinfo, dan getaddrinfo menelusuri rantai yang lebih panjang: urutan modul nsswitch, lalu modul yang menangani nama, lalu resolver yang dibangun dari konfigurasi tautan saat ini. Pada mesin systemd kueri pergi ke 127.0.0.53 dan systemd-resolved memilih server hulu per tautan berdasarkan domain perutean yang dilekatkan pada antarmuka tun.
Dua perintah memisahkan lapisan itu tanpa menebak:
getent ahosts service.internal.example
resolvectl query service.internal.example
getent memakai jalur yang sama dengan curl, jadi kegagalan getent di samping dig yang berfungsi melokalisasi kesalahan pada kebijakan pencarian, bukan pada perutean paket. resolvectl query juga mencetak antarmuka dan server hulu yang memberi jawaban, yang menunjukkan apakah tautan tunnel atau tautan fisik memenangkan keputusan.
Baca resolver yang benar-benar dipakai aplikasi
/etc/resolv.conf dihasilkan pada sebagian besar desktop, dan klien VPN punya tiga cara berinteraksi dengannya: menambahkan server nama di depan, menimpa berkas, atau menyerahkan servernya kepada NetworkManager dan membiarkan daemon menulis ulang. Hanya pola ketiga yang mempertahankan DNS per tautan, karena server tetap terikat pada antarmuka alih-alih diratakan ke dalam satu daftar global.
Pada sistem NetworkManager hasilnya bergantung pada backend di /etc/NetworkManager/NetworkManager.conf:
[main]
dns=systemd-resolved
Dengan dns=default server klien digabungkan ke resolv.conf dalam urutan yang menang, dan pencarian privat masih bisa dikirim ke resolver publik. Dengan backend yang memahami tautan, systemd-resolved atau dnsmasq, server tunnel tetap dibatasi pada tunnel dan hanya nama yang cocok dengan domain peruteannya yang pergi ke sana. Pembatasan itulah arti split DNS dalam praktik, dan itulah bagian yang paling sering hilang ketika klien mengaku mendukungnya.
Baca keadaan sebelum mengubah apa pun:
resolvectl status
resolvectl dns tun0
Anda ingin melihat antarmuka tun terdaftar dengan server DNS dan domain perutean untuk sufiks privat, ditampilkan sebagai ~internal.example. Tidak ada server pada tautan berarti klien tidak mengirim apa pun. Server tanpa domain berarti kueri entah semuanya pergi ke sana atau tidak sama sekali, tergantung klien, dan keduanya bukan split DNS.
Tempat nsswitch mengakhiri pencarian terlalu dini
Baris desktop standar tampak seperti ini:
hosts: files mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns myhostname
mdns4_minimal menangani multicast DNS dan mengklaim setiap nama yang berakhiran .local. Layanan Kubernetes seperti api.infra.svc.cluster.local juga berakhiran .local. Ketika modul mDNS melaporkan NOTFOUND, aksi [NOTFOUND=return] mengakhiri seluruh pencarian alih-alih melanjutkan ke modul dns, sehingga nama tidak pernah dikirim ke resolver VPN. dig melewati berkas itu sepenuhnya, dan itulah sebabnya kedua alat tidak sepakat.
Itulah kontras paling tajam dalam masalah ini, dan semuanya bermuara pada satu kata dalam berkas konfigurasi yang lebih tua daripada VPN Anda. Mengubah aksi menjadi [NOTFOUND=continue] mempertahankan mDNS untuk printer dan perangkat lokal sekaligus membiarkan DNS melihat nama. Mengganti baris dengan hosts: files dns juga berfungsi dan lebih kasar: ia membuang resolusi .local untuk printer yang benar-benar Anda pakai.
Nama yang hidup di tepat satu jaringan
Zona privat berotoritas di tepat satu tempat. Nama AWS seperti ip-10-0-4-31.eu-west-1.compute.internal dijawab melalui resolver VPC wilayah itu, dan hanya selama endpoint VPN Anda berada di wilayah yang sama dengan sumber dayanya. Sambungkan ke endpoint di Frankfurt, kueri nama compute.internal dari Irlandia, dan tidak ada pengaturan lokal yang menolong: zona yang menyimpan catatan itu tidak terjangkau dari sana.
Domain pencarian menghasilkan gambar cermin. service telanjang dilengkapi dengan sufiks yang dianggap berlaku oleh resolver, dan dengan tautan VPN domain lokal bisa mengalahkan domain korporat. Kueri dengan titik di akhir untuk membuang tebakan, getent ahosts service.internal.example., dan jika itu berhasil sementara nama pendek gagal, perbaikannya adalah domain pencarian pada tunnel, bukan alamat server.
Klien terkelola menambahkan lapisan ketiga di atas resolver sistem. Profil VPN Windows dapat membawa kebijakan resolusi nama sendiri, aturan per aplikasi, dan tabel NRPT yang berlaku bahkan saat tunnel mati. Aplikasi dengan tembolok DNS sendiri, umum di runtime .NET dan Java, menyimpan kegagalan basi lama setelah rantai diperbaiki. Klien Apple mengonfigurasi split DNS melalui domain pencocokan di pengaturan DNS alih-alih lewat resolv.conf, dan Chromium atau Firefox dalam mode DNS aman dapat melewati resolver sistem untuk nama publik. Referensi Microsoft tentang resolusi nama VPN menjelaskan sisi Windows dari lapisan kebijakan itu.
Putuskan lapisan mana yang diperbaiki
Bekerjalah dari gejala ke lapisan alih-alih mencoba perbaikan berurutan:
| Symptom | What it means | Check first |
|---|---|---|
| dig answers, getent fails | lookup chain, not the packet path | nsswitch line and resolvectl status |
| Timeout rather than NXDOMAIN | private resolver unreachable through the tunnel | resolvectl dns tun0, route to that address |
| NXDOMAIN | an authority answered and does not know the name | zone owner, endpoint region |
| FQDN works, short name fails | search suffix mismatch | resolvectl domain on the tun link |
| getent works, app fails | app cache or its own resolver | restart the app, check secure DNS |
Dua baris memikul sebagian besar beban. Timeout adalah masalah keterjangkauan: resolver privat tidak menjawab melalui tunnel, jadi periksa rute ke alamatnya dan apakah server DNS pada tautan itu yang Anda kira. NXDOMAIN adalah masalah otoritas: sesuatu menjawab dan tidak mengenal nama itu, yang mengarah ke zona, wilayah, atau resolver yang seharusnya tidak pernah menerima kueri tersebut.
Baris terakhir adalah yang orang lewatkan karena kedua belah pihak tampak seperti keberhasilan. Nama pendek yang beresolusi berbeda dari FQDN adalah ketidakcocokan sufiks, dan menyambung ulang tunnel tidak akan mengubah sufiks yang dikirim klien.
Catat keadaan sebelum menyunting berkas konfigurasi, agar Anda bisa mengatakan apakah suntingan itu berpengaruh:
resolvectl status > before.txt
getent ahosts service.internal.example >> before.txt
Jalankan pemeriksaan dalam urutan ini dan berhenti pada kegagalan pertama. getent dan resolvectl query harus sepakat; jika getent gagal sementara dig menjawab, tetaplah di rantai pencarian dan jangan sentuh perutean. resolvectl status harus menunjukkan server DNS dan domain perutean pada antarmuka tun. nsswitch tidak boleh kembali lebih awal dengan NOTFOUND untuk sufiks yang sedang diuji. Nama harus berotoritas di jaringan tempat endpoint Anda terpasang, diuji dengan titik di akhir. Aplikasi tidak boleh menyimpan tembolok sendiri atau penggantian DNS aman.
Perbaiki hanya lapisan pertama yang gagal, lalu jalankan lagi perintah yang sama. Dua perubahan sekaligus membuat Anda tidak bisa mengatakan mana yang berpengaruh, dan gangguan berikutnya memulai penyelidikan dari nol.