Ứng dụng Android phân giải tên ngoài VPN: danh sách kiểm tra liên kết
Android có thể phân giải tên qua mạng mặc định khi VPN đang bật. Liên kết tiến trình với mạng VPN và kiểm tra xem ứng dụng thực sự đã dùng resolver nào.
Một ứng dụng Android không phân giải được tên nội bộ trong khi trình duyệt của chính ứng dụng VPN vẫn truy cập được, và cùng bản dựng đó lại chạy được trên máy khác. URL không phải biến số. Biến số là mạng mà tiến trình của ứng dụng được phép dùng để phân giải, và Android không bảo đảm rằng VPN đang hoạt động chính là mạng mà các socket của bạn dùng. Hãy làm các kiểm tra này theo thứ tự và dừng lại khi ảnh chụp resolver không khớp với giả định của bạn.
Bước 1: chứng minh ứng dụng đang ở mạng nào
Đọc khung nhìn của chính ứng dụng, không phải thanh trạng thái. Từ ConnectivityManager, lấy mạng đang hoạt động, LinkProperties của nó, danh sách máy chủ DNS và thiết lập DNS riêng tư. Nếu danh sách có resolver của VPN, ứng dụng có đường tới đó; nếu danh sách có resolver của Wi-Fi, đường hầm không phải mạng mặc định của tiến trình đó.
Biểu tượng VPN chỉ nói rằng có một đường hầm. Nó không nói rằng tiến trình của ứng dụng đã được liên kết với đường hầm đó, và Android không phải lúc nào cũng định tuyến việc phân giải tên qua mạng trông có vẻ đang hoạt động. Ứng dụng VPN cục bộ chuyển tiếp sang thiết bị khác, mạng Wi-Fi không có internet và bản dựng của nhà sản xuất đều có thể khiến ứng dụng hỏi resolver mặc định thay vì máy chủ của đường hầm.
Bước 2: yêu cầu transport VPN và liên kết tiến trình
Khi ứng dụng buộc phải dùng resolver của đường hầm, hãy yêu cầu một mạng có transport VPN và liên kết tiến trình trong callback, để mã không đoán khi nào mạng xuất hiện:
val request = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.build()
connectivityManager.requestNetwork(request, object : NetworkCallback() {
override fun onAvailable(network: Network) {
val bound = connectivityManager.bindProcessToNetwork(network)
Log.i(TAG, "bound to VPN network: " + bound)
}
})
Lệnh gọi này thay đổi mạng mặc định của toàn bộ tiến trình, nên mọi socket tạo sau đó đều dùng nó. Những socket đã tồn tại giữ nguyên mạng mà chúng được tạo ra, đó là lý do một pool kết nối mở trước khi liên kết có thể tiếp tục phân giải theo đường cũ. Giá trị trả về là boolean, và kết quả false nghĩa là việc liên kết không xảy ra; hãy thử lại với một độ trễ ngắn và ghi lại cả hai lần thử.
Bước 3: giới hạn liên kết trong phạm vi cần thiết
Liên kết toàn tiến trình là thô. Telemetry, kiểm tra cập nhật và SDK bên thứ ba cũng chuyển sang đường hầm, và nếu đường hầm không có internet thì chúng bắt đầu thất bại. Với một yêu cầu duy nhất, hãy dùng socket factory của mạng và giữ mặc định của thiết bị cho mọi thứ khác. Chọn có chủ đích một mô hình: liên kết hẹp theo từng kết nối, hoặc liên kết tiến trình với việc bỏ liên kết rõ ràng khi VPN biến mất.
Hai tính năng của resolver có thể đánh bại liên kết mà không có lỗi nào. DNS riêng tư ở chế độ nghiêm ngặt gửi truy vấn tới một máy chủ DoT có tên thay vì resolver của mạng, và ứng dụng mang theo ứng dụng khách DNS-over-HTTPS của riêng mình sẽ bỏ qua hoàn toàn resolver của hệ thống. Hãy kiểm tra cả hai trước khi kết luận liên kết thất bại. Một truy vấn không bao giờ tới máy chủ DNS của VPN sẽ không xuất hiện trong bất kỳ nhật ký nào phía đường hầm.
Bước 4: đừng tin ràng buộc CONNECTED
NetworkType.CONNECTED trong WorkManager nghĩa là có một mạng đang kết nối, và transport VPN thỏa mãn điều đó ngay cả khi liên kết Wi-Fi hay di động bên dưới đã mất. Tác vụ chạy, mọi yêu cầu thất bại, và chính sách thử lại biến nó thành một cơn bão trông như lỗi lập lịch. Đường hầm là một mạng; ràng buộc đó chưa bao giờ là kiểm tra internet.
Hãy kiểm tra năng lực mà công việc thực sự cần, ví dụ truy cập internet đã được xác thực, và giữ chính sách thử lại có giới hạn với backoff. Nếu công việc cần một tên riêng tư, hãy phân giải tên đó trong mạng đã chọn trước khi làm việc, và thất bại nhanh với lỗi rõ ràng thay vì lặp lại một yêu cầu không thể thành công.
Bước 5: ghi lại bằng chứng và kiểm tra lại dải phiên bản
Ghi lại các loại transport của mạng đã chọn, máy chủ DNS từ LinkProperties, việc liên kết có trả về true hay không, và lỗi chính xác của yêu cầu đầu tiên. Sau đó chạy một tên riêng tư và một tên công khai dưới cùng liên kết. Cặp đó cho thấy ứng dụng đã dùng resolver của đường hầm hay âm thầm quay về mặc định của thiết bị, và đó chính là khác biệt mà người dùng cảm nhận.
Lặp lại trên phiên bản Android cũ nhất mà bạn hỗ trợ và trên một bản phát hành hiện tại. Hành vi resolver khiến đường mặc định trông đúng chính là nơi thiết bị và phiên bản khác nhau, và một bản dựng chỉ đạt trên thiết bị kiểm thử mới nhất thì chưa được xác minh cho dải mà bạn phát hành. adb shell dumpsys connectivity là cách nhanh để xác nhận thiết bị báo cáo những mạng và năng lực nào khi bạn tái hiện lỗi.