Vì sao tên máy chủ nội bộ phân giải được trong dig nhưng thất bại trong curl trên VPN
dig trả lời nhưng curl báo không thể phân giải máy chủ. Hãy so sánh hai chuỗi tra cứu, rồi sửa nsswitch, DNS theo liên kết hoặc hậu tố tìm kiếm sai.
Laptop của bạn đang ở trên VPN, dig service.internal.example trả lời bằng địa chỉ 10.x, và curl vẫn kết thúc với Could not resolve host. Đường hầm không phải là vấn đề: nó đã chuyển truy vấn dig mà không phàn nàn. Khác biệt là ai đặt câu hỏi. dig gửi một truy vấn tới một máy chủ mà bạn chỉ định, còn curl đi qua chuỗi tra cứu của hệ điều hành, và chuỗi đó có quy tắc riêng về việc máy chủ nào được hỏi.
Hai lần tra cứu cho cùng một tên
dig là stub resolver của riêng nó. Nó đọc /etc/resolv.conf, chọn một máy chủ tên, gửi một truy vấn A hoặc AAAA và in ra câu trả lời. Nó bỏ qua hoàn toàn nsswitch và không biết gì về trạng thái theo liên kết mà systemd-resolved hoặc NetworkManager giữ ngoài tệp đó, vì thế câu trả lời của dig có thể đúng mà vẫn không cho bạn biết gì về những gì ứng dụng của bạn sẽ thấy.
Các ứng dụng gọi getaddrinfo, và getaddrinfo đi qua một chuỗi dài hơn: thứ tự mô-đun của nsswitch, rồi mô-đun xử lý tên, và cuối cùng là resolver được dựng từ cấu hình liên kết hiện tại. Trên máy systemd truy vấn đi tới 127.0.0.53 và systemd-resolved chọn máy chủ thượng nguồn cho từng liên kết dựa trên miền định tuyến gắn với giao diện tun.
Hai lệnh tách các lớp đó mà không phải đoán:
getent ahosts service.internal.example
resolvectl query service.internal.example
getent dùng cùng đường đi như curl, nên một lỗi getent bên cạnh dig đang hoạt động sẽ khoanh vùng sự cố vào chính sách tra cứu chứ không phải định tuyến gói tin. resolvectl query cũng in ra giao diện và máy chủ thượng nguồn đã cung cấp câu trả lời, điều này cho thấy liên kết đường hầm hay liên kết vật lý đã thắng quyết định.
Đọc resolver mà ứng dụng thực sự dùng
/etc/resolv.conf được tạo trên hầu hết máy tính để bàn, và một ứng dụng khách VPN có ba cách tương tác với nó: thêm một máy chủ tên lên đầu, ghi đè tệp, hoặc giao các máy chủ của mình cho NetworkManager và để tiến trình nền viết lại. Chỉ cách thứ ba giữ được DNS theo liên kết, vì các máy chủ vẫn gắn với một giao diện thay vì bị làm phẳng thành một danh sách toàn cục.
Trên các hệ NetworkManager kết quả phụ thuộc vào backend trong /etc/NetworkManager/NetworkManager.conf:
[main]
dns=systemd-resolved
Với dns=default các máy chủ của ứng dụng khách bị gộp vào resolv.conf theo thứ tự thắng cuộc, và một truy vấn riêng tư vẫn có thể bị gửi tới resolver công cộng. Với backend hiểu về liên kết, systemd-resolved hoặc dnsmasq, các máy chủ của đường hầm vẫn bị giới hạn trong đường hầm và chỉ những tên khớp với miền định tuyến của nó mới đi tới đó. Sự giới hạn đó chính là ý nghĩa của split DNS trong thực tế, và đó là phần thường thiếu nhất khi một ứng dụng khách tuyên bố hỗ trợ nó.
Đọc trạng thái trước khi sửa bất cứ điều gì:
resolvectl status
resolvectl dns tun0
Bạn muốn thấy giao diện tun được liệt kê với một máy chủ DNS và một miền định tuyến cho hậu tố riêng, hiển thị là ~internal.example. Không có máy chủ trên liên kết nghĩa là ứng dụng khách không đẩy gì cả. Một máy chủ không có miền nghĩa là các truy vấn hoặc đều đi tới đó hoặc không đi chút nào, tùy ứng dụng khách, và cả hai đều không phải split DNS.
Nơi nsswitch kết thúc tra cứu quá sớm
Một dòng tiêu chuẩn trên máy để bàn trông như thế này:
hosts: files mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns myhostname
mdns4_minimal xử lý multicast DNS và nhận mọi tên kết thúc bằng .local. Một dịch vụ Kubernetes như api.infra.svc.cluster.local cũng kết thúc bằng .local. Khi mô-đun mDNS báo NOTFOUND, thao tác [NOTFOUND=return] kết thúc toàn bộ lần tra cứu thay vì chuyển tiếp sang mô-đun dns, nên tên không bao giờ được gửi tới resolver của VPN. dig bỏ qua tệp hoàn toàn, và đó chính là lý do hai công cụ không đồng ý với nhau.
Đó là tương phản sắc nét nhất trong vấn đề này, và nó quy về một từ trong tệp cấu hình cũ hơn VPN của bạn. Đổi thao tác thành [NOTFOUND=continue] giữ mDNS cho máy in và thiết bị cục bộ trong khi cho phép DNS thấy tên. Thay dòng bằng hosts: files dns cũng hiệu quả và thô hơn: nó bỏ phân giải .local cho chiếc máy in mà bạn thực sự dùng.
Những cái tên chỉ sống trong đúng một mạng
Các miền riêng có thẩm quyền ở đúng một nơi. Một tên AWS như ip-10-0-4-31.eu-west-1.compute.internal được trả lời qua resolver VPC của vùng đó, và chỉ khi điểm cuối VPN của bạn ở cùng vùng với tài nguyên. Kết nối tới một điểm cuối ở Frankfurt, hỏi một tên compute.internal từ Ireland, và không cấu hình cục bộ nào giúp được: miền giữ bản ghi không thể vươn tới từ đó.
Các miền tìm kiếm tạo ra hình ảnh ngược lại. Một service trần được hoàn thiện bằng hậu tố mà resolver cho là phù hợp, và với một liên kết VPN miền cục bộ có thể thắng miền doanh nghiệp. Hãy hỏi với dấu chấm ở cuối để bỏ phỏng đoán, getent ahosts service.internal.example., và nếu điều đó hiệu quả trong khi tên ngắn thất bại, cách sửa là miền tìm kiếm trên đường hầm, không phải địa chỉ máy chủ.
Các ứng dụng khách được quản lý thêm một lớp thứ ba bên trên resolver của hệ điều hành. Một hồ sơ VPN của Windows có thể mang chính sách phân giải tên riêng, quy tắc theo từng ứng dụng và bảng NRPT vẫn áp dụng cả khi đường hầm đã tắt. Các ứng dụng có bộ nhớ đệm DNS riêng, phổ biến trong môi trường .NET và Java, giữ lại một lỗi cũ rất lâu sau khi chuỗi đã được sửa. Ứng dụng khách Apple cấu hình split DNS qua miền khớp trong cài đặt DNS thay vì qua resolv.conf, còn Chromium hoặc Firefox ở chế độ DNS an toàn có thể bỏ qua resolver của hệ thống cho các tên công cộng. Tài liệu tham chiếu của Microsoft về phân giải tên VPN mô tả phía Windows của lớp chính sách đó.
Quyết định sửa lớp nào
Đi từ triệu chứng tới lớp thay vì thử các cách sửa theo thứ tự:
| 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 |
Hai hàng gánh phần lớn trọng lượng. Hết thời gian chờ là vấn đề khả năng tiếp cận: resolver riêng không trả lời qua đường hầm, nên hãy kiểm tra tuyến tới địa chỉ của nó và xem máy chủ DNS trên liên kết có đúng là cái bạn nghĩ không. NXDOMAIN là vấn đề thẩm quyền: có thứ gì đó trả lời và nó không biết tên, điều này chỉ vào miền, vùng hoặc một resolver lẽ ra không bao giờ được nhận truy vấn.
Hàng cuối là hàng người ta bỏ qua vì cả hai nửa đều trông như thành công. Một tên ngắn phân giải khác với FQDN là sự không khớp hậu tố, và kết nối lại đường hầm sẽ không đổi hậu tố mà ứng dụng khách gửi đi.
Ghi lại trạng thái trước khi sửa tệp cấu hình, để bạn có thể nói liệu thay đổi có tác dụng gì không:
resolvectl status > before.txt
getent ahosts service.internal.example >> before.txt
Chạy các kiểm tra theo thứ tự này và dừng ở lần hỏng đầu tiên. getent và resolvectl query phải khớp nhau; nếu getent hỏng trong khi dig trả lời, hãy ở lại trong chuỗi tra cứu và đừng chạm vào định tuyến. resolvectl status phải cho thấy một máy chủ DNS và một miền định tuyến trên giao diện tun. nsswitch không được trả về sớm với NOTFOUND cho hậu tố bạn đang thử. Tên phải có thẩm quyền trong mạng mà điểm cuối của bạn gắn vào, được kiểm tra với dấu chấm ở cuối. Ứng dụng không được giữ bộ nhớ đệm riêng hay một sự ghi đè DNS an toàn.
Chỉ sửa lớp hỏng đầu tiên, rồi chạy lại đúng những lệnh đó. Hai thay đổi cùng lúc khiến bạn không thể nói cái nào mới quan trọng, và sự cố tiếp theo bắt đầu điều tra từ con số không.