VPN đang bật, giao diện web riêng trả lời qua IPv6 từ máy tính xách tay, và điện thoại Android vẫn mở đúng trang đó qua IPv4 hoặc từ chối tải hoàn toàn. Bản ghi AAAA tồn tại. Đường hầm báo một địa chỉ IPv6. Không có gì trong ứng dụng khách trông sai. Kết quả do bốn quyết định riêng rẽ định đoạt: bộ phân giải nào đã trả lời, VpnService đã khai báo gì với Android, trình duyệt sẵn sàng thử họ địa chỉ nào, và gói tin có thể thực hiện chuyến đi khứ hồi hay không. Hãy xử lý theo thứ tự đó thay vì thêm một tuyến mặc định và hy vọng triệu chứng sẽ dịch chuyển.

Bước 1: chứng minh bộ phân giải nào đã trả lời truy vấn AAAA

Android không có một đường DNS duy nhất. VPN có thể đẩy một máy chủ DNS cho mạng của mình, hệ thống có thể dùng Private DNS cho các tên máy chủ mà nó thấy phù hợp, và Chrome có thể chạy bộ phân giải mã hóa của riêng nó từ chrome://settings/security. Trên một điện thoại mà đường hầm đẩy 10.61.0.1 nhưng Private DNS trỏ tới một nhà cung cấp công cộng, tên bên trong vùng riêng của bạn không được phân giải bởi máy sở hữu vùng đó. Trình duyệt nhận câu trả lời từ một bộ phân giải không có thẩm quyền với tên đó và coi là không tồn tại, và văn bản lỗi không bao giờ nhắc tới DNS.

Hãy hỏi trực tiếp bộ phân giải của đường hầm trước khi thay đổi bất cứ điều gì khác. Hai lệnh đầu cho biết Android đã gắn máy chủ DNS nào vào mạng đang hoạt động và Private DNS ở chế độ tự động hay nghiêm ngặt; lệnh thứ ba chạy từ bất kỳ ứng dụng khách nào bên trong đường hầm, không phải từ điện thoại.

adb shell dumpsys connectivity | grep -A3 "DnsAddresses"
adb shell settings get global private_dns_mode
nslookup -type=AAAA nas.lan 10.61.0.1

Bước 2: đọc xem VpnService thực sự đã khai báo gì

Phía Android là tường minh chứ không phải suy đoán. VpnService.Builder thêm địa chỉ bằng addAddress, tuyến đường bằng addRoute, máy chủ DNS bằng addDnsServer, và có thể giới hạn toàn bộ đường hầm vào một họ địa chỉ bằng allowFamily. Một builder đã gọi allowFamily(AF_INET) rồi sau đó thêm tuyến IPv6 đã nói với hệ thống hai điều mâu thuẫn, và hệ thống giữ lại giới hạn họ địa chỉ. Một tuyến bao phủ fd00:61::/64 kết hợp với địa chỉ giao diện ở tiền tố khác sẽ thất bại vì lý do tương tự: địa chỉ tồn tại nhưng nó không on-link cho tuyến đó.

Hãy đọc khai báo thay vì tin vào công tắc trong ứng dụng. dumpsys netd in ra các địa chỉ và tuyến gắn với giao diện tun, và LinkProperties theo từng mạng bên trong dumpsys connectivity hiển thị danh sách DNS bên cạnh các họ mà mạng tự nhận.

adb shell ip -6 addr show tun0
adb shell ip -6 route show table all | grep tun0
adb shell dumpsys connectivity | grep -E "LinkAddresses|Routes"

Nếu giao diện tun có địa chỉ IPv6 nhưng không tuyến nào khớp với tiền tố của dịch vụ, việc giao IPv6 đã hỏng trước khi trình duyệt tham gia. Đây là lỗi khác với trình duyệt từ chối thử, và cần cách sửa khác.

Bước 3: trình duyệt quyết định có thử IPv6 hay không

Chromium không dùng mọi bản ghi AAAA mà nó nhận được. Bộ phân giải máy chủ của nó mang theo các kiểm tra khả năng tiếp cận IPv6 và lọc ứng viên, có thể loại bỏ hoặc hạ ưu tiên IPv6 khi mạng bị đánh giá là không thể mang nó, và mã nguồn bộ phân giải cho thấy phép thử đó cùng các điều kiện xung quanh. Logic phụ thuộc vào phiên bản và cờ, và chính vì thế hai điện thoại trên cùng một đường hầm có thể hành xử khác nhau. Khi đã có ứng viên, Happy Eyeballs cho các họ đua nhau theo từng kết nối, nên một tuyến IPv6 trả lời chậm vẫn có thể thua IPv4 trả lời nhanh.

Hãy quan sát quyết định thay vì suy đoán. Một phiên được ghi qua chrome://net-export và phát lại trong trình xem netlog cho thấy từng lần phân giải và họ được chọn; chrome://net-internals/#dns hiển thị kết quả trong bộ nhớ đệm. Một lần phân giải chỉ trả về bản ghi A cho tên có AAAA ở bộ phân giải của chính bạn chỉ thẳng vào giai đoạn này.

Bước 4: xác minh gói tin có thể thực hiện chuyến đi khứ hồi

Chọn địa chỉ không phải là giao hàng. Android giữ bảng định tuyến và quy tắc chính sách theo từng mạng để chọn bảng theo fwmark, nên một tuyến hiển thị trong bảng chính không tự động là tuyến mà socket dùng. Đọc các quy tắc và yêu cầu nhân phân giải đích cho một địa chỉ nguồn sẽ tách hai điều đó ra.

adb shell ip -6 rule show
adb shell ip -6 route get fd00:61::20 from fd00:61::10

Chính đầu ra của route get trả lời câu hỏi. Nếu nó nêu tun0 mà gói vẫn chết, hãy chuyển sang MTU của đường hầm và việc chuyển tiếp IPv6 ở cổng, thay vì quay lại điện thoại.

Vì sao thêm ::/0 thường làm mọi thứ tệ hơn

Thêm ::/0 thay đổi yêu cầu của đường hầm từ một tiền tố sang mọi đích IPv6. Trên điện thoại, điều đó có thể thỏa mãn một phép thử khả năng tiếp cận, vì một địa chỉ thử ngoài tiền tố của bạn giờ trông như có thể định tuyến. Nó không tạo ra dung lượng IPv6 thượng nguồn ở cổng, và nhiều cổng trong nhà không có đường lên IPv6 hoạt động nào. Kết quả là một hố đen với IPv6 công cộng: những tên trước đây rơi về IPv4 giờ bị treo, và trang riêng có thể trông tốt hơn chỉ vì phép thử đang đo một thứ khác.

Cũng có chi phí chính sách. Với ::/0 trong đường hầm, toàn bộ lưu lượng IPv6 đi ra qua VPN, kể cả lưu lượng mà chủ mạng chưa bao giờ đồng ý mang. Hãy coi đó là quyết định triển khai có chủ sở hữu được nêu tên, không phải một bước gỡ lỗi bạn làm lúc 1 giờ sáng.

Trình tự công việc kết thúc chuyện này

Xác nhận câu trả lời AAAA đến từ bộ phân giải giữ vùng, đọc trạng thái VpnService và netd cho giao diện tun, ghi một dấu vết net-export để xem Chromium có loại ứng viên hay không, rồi thử chuyến đi khứ hồi với ip -6 route get. Sửa tầng thực sự đã hỏng và để yên chính sách chia tách. Nếu tên riêng cần câu trả lời khác tên công cộng, split tunneling chính là để làm việc đó.

Ghi lại bản dựng của điện thoại, phiên bản trình duyệt và bộ phân giải bạn đã hỏi. Ba sự thật đó biến "IPv6 is broken" thành thứ mà người tiếp theo có thể tái tạo.

Bài viết liên quan