Vì sao resolv.conf hiển thị DNS của VPN nhưng các truy vấn lại bỏ qua nó
Trên máy chủ có resolved, tệp này là một góc nhìn chứ không phải trạng thái. Hãy theo dõi stub, các máy chủ theo từng liên kết và dòng nsswitch để xem truy vấn thực sự dùng cái nào.
Không có gì trông sai trong nhật ký: giao diện đang hoạt động, trình phân giải báo máy chủ DNS của VPN, và tệp trên đĩa liệt kê nó. Vậy mà một tên máy chủ nội bộ vẫn được phân giải qua bộ định tuyến cục bộ. Ba phát biểu này không mâu thuẫn, vì tệp, trạng thái của từng liên kết và đường đi của truy vấn là những đối tượng khác nhau tình cờ dùng chung một cái tên. Phần tiếp theo mô tả đường đi mà một truy vấn thực sự đi trên máy chủ có systemd-resolved.
Ba đối tượng mang tên resolv.conf
Trên máy chủ có resolved, /etc/resolv.conf thường là một liên kết tượng trưng tới /run/systemd/resolve/stub-resolv.conf. Đích đó chứa địa chỉ của một trình lắng nghe stub cục bộ, 127.0.0.53, cùng các miền tìm kiếm do resolved tính toán. Đây là góc nhìn về trạng thái, không phải bản thân trạng thái.
Trạng thái sống trong cấu hình của resolved theo từng liên kết, và đó là lý do resolvectl status có thể không khớp với tệp mà vẫn đúng. Mỗi liên kết mang máy chủ riêng và miền định tuyến riêng, và stub tham chiếu dữ liệu đó khi một truy vấn đến. Hướng dẫn của systemd-resolved mô tả các tệp được tạo và mô hình theo từng liên kết; việc tách góc nhìn khỏi trạng thái là phần đáng ghi nhớ. Sửa đích của liên kết tượng trưng thay đổi thứ mà các ứng dụng khách truyền thống đọc, không phải thứ trình phân giải biết.
Đối tượng thứ ba, /run/systemd/resolve/resolv.conf, làm phẳng mỗi liên kết thành một danh sách máy chủ duy nhất. Một chương trình trỏ tới tệp đó gửi truy vấn thẳng tới các máy chủ được liệt kê và bỏ qua stub, nên chính sách theo từng liên kết không còn áp dụng cho nó. Vì vậy hai chương trình trên cùng một máy có thể trả lời cùng một tên theo cách khác nhau, và không cái nào bị hỏng.
Theo dõi một truy vấn qua NSS
glibc đọc /etc/nsswitch.conf để quyết định ai trả lời một tên. Dòng hosts có chứa resolve chuyển câu hỏi tới nss-resolve, nơi hỏi resolved qua D-Bus và nhận câu trả lời theo liên kết. Dòng chỉ có files dns gửi truy vấn tới địa chỉ mà /etc/resolv.conf nắm giữ.
Chính dòng đó giải thích phần lớn bất đồng giữa trình duyệt và dig. dig đọc resolv.conf trực tiếp và không bao giờ chạm vào NSS, nên nó kiểm tra stub hoặc một máy chủ thượng nguồn thay vì đường đi mà ứng dụng dùng. getent hosts internal.example đi qua NSS, và so sánh câu trả lời của nó với câu trả lời của dig là phép đo hữu ích đầu tiên.
Những ứng dụng mang theo trình phân giải riêng, hoặc nói DNS qua HTTPS tới một điểm cuối cố định, sẽ bỏ qua cả hai đường. Không có gì trong resolv.conf hay trong trạng thái của resolved ràng buộc chúng.
Kiểm tra ai sở hữu tệp và nó trỏ tới đâu
Đọc chuỗi liên kết trước khi thay đổi bất cứ điều gì, vì quyền sở hữu quyết định tệp nào có thẩm quyền. Mọi lệnh bên dưới chỉ đọc trạng thái.
stat -c '%N' /etc/resolv.conf
resolvectl status --no-pager
grep '^hosts' /etc/nsswitch.conf
ls -l /run/systemd/resolve/
Dòng đầu in ra liên kết và đích của nó cùng nhau, và một tệp thường do script VPN sở hữu nghĩa là trình phân giải không bao giờ coi lần ghi đó là đầu vào. Kết quả của trạng thái liệt kê máy chủ theo từng liên kết cùng các miền định tuyến quyết định mỗi truy vấn đi đâu. Dòng nsswitch cho biết stub có được tham chiếu hay không, nên một địa chỉ stub trong tệp mà không có resolve ở đó nghĩa là các truy vấn tới được trình lắng nghe cục bộ trong khi không có gì quản lý việc tách. Danh sách cuối đó cũng quan trọng, vì máy chủ không có stub-resolv.conf không chạy cách bố trí được mô tả ở đây.
Nếu chuỗi kết thúc ở một tệp do gói khác quản lý, ứng dụng khách VPN và gói đó là hai chủ sở hữu cần hòa giải. Thay liên kết sẽ vứt bỏ công việc của một chủ sở hữu và để nguyên công việc của chủ kia.
Sửa tại chủ sở hữu của liên kết
Một kết nối VPN nên đăng ký máy chủ và miền của nó trên liên kết của chính nó, rồi rút chúng đi khi ngắt kết nối. Tích hợp resolved của NetworkManager và trình trợ giúp riêng của ứng dụng khách đều hoạt động như vậy; một script chỉ ghi lại resolv.conf thì không.
Trên một liên kết đã tồn tại, cấu hình lúc chạy cho thấy cơ chế. resolvectl dns tun0 10.40.0.53 gắn một máy chủ, và resolvectl domain tun0 '~corp.example' gắn một miền định tuyến. Dấu ngã là ký tự chịu lực: nó giới hạn truy vấn cho hậu tố đó trong liên kết này và để mọi thứ khác yên, trong khi cùng giá trị đó không có nó sẽ trở thành miền tìm kiếm và việc tách biến mất. Những địa chỉ đó là ví dụ phòng thí nghiệm, không phải cấu hình lâu dài. Xác nhận bằng resolvectl query host.corp.example và đọc xem liên kết nào đã trả lời.
Một máy chủ đã đăng ký vẫn cần một tuyến đường. Khi truy vấn tới đúng liên kết rồi hết thời gian chờ, lỗi nằm ở khả năng tiếp cận qua đường hầm chứ không phải ở quyền sở hữu của trình phân giải.
Trạng thái hoạt động trông như thế nào
Một kết quả khỏe mạnh là nhất quán ở cả ba góc nhìn: máy chủ theo từng liên kết khớp với thứ VPN đã cấp, các miền định tuyến chỉ bao phủ hậu tố nội bộ, và ứng dụng quan trọng phân giải được một tên nội bộ trong khi tên công cộng vẫn đi theo đường cục bộ. Một truy vấn thành công chứng minh ít hơn sự đồng thuận đó.
Sau đó hãy ngắt kết nối và lặp lại cả hai truy vấn. Một ứng dụng khách để các miền của mình vẫn đăng ký sau khi tháo gỡ sẽ tạo ra một máy hỏng việc phân giải nội bộ nhiều giờ sau đó, không có đường hầm mở và không có nguyên nhân rõ ràng.