Android always-on VPN: vì sao tên điểm cuối được phân giải trước
Android chặn lưu lượng trước khi đường hầm tồn tại, nhưng máy khách vẫn phải phân giải điểm cuối của mình. Đây là thứ tự, và nơi nó bế tắc.
Điện thoại khởi động lại, always-on đang bật, «chặn kết nối khi không có VPN» đang bật, và đường hầm không bao giờ lên. Không có gì cấu hình sai: việc chặn đang làm đúng việc của nó, và nỗ lực của chính máy khách để tới điểm cuối của mình cũng chịu sự chi phối đó. Tên điểm cuối phải được phân giải trước khi đường hầm tồn tại, bởi một máy khách được phép nói chuyện với mạng trong khi mọi ứng dụng khác thì không. Hiểu thành phần nào làm việc đó, và theo thứ tự nào, là điều biến câu đố này thành một câu hỏi cấu hình.
Trình dựng VPN thực sự yêu cầu điều gì
Ứng dụng VPN Android không trao cho nền tảng địa chỉ máy chủ. Nó dựng một giao diện cục bộ: địa chỉ và tuyến cho đường hầm, các bộ phân giải mà ứng dụng nên dùng bên trong nó, rồi establish() trả về một bộ mô tả tệp mà ứng dụng đọc và ghi dưới dạng gói IP thô. Điểm cuối từ xa hoàn toàn không xuất hiện trong trình dựng đó.
Đó là sự thật cấu trúc then chốt. Nền tảng tạo giao diện tun và áp chính sách lên đó; ứng dụng hiện thực việc truyền tải trong không gian người dùng, nghĩa là chính ứng dụng phân giải tên điểm cuối và mở kết nối mã hóa. Vì vậy điểm cuối dưới dạng tên máy chủ là khả thi — không phải vì nền tảng hỗ trợ tên, mà vì nền tảng không bao giờ thấy điểm cuối.
Một trường trong trình dựng có nhận địa chỉ: các máy chủ DNS. Chúng phải là địa chỉ bộ phân giải dạng số, thường là những địa chỉ mà nhà vận hành muốn hỏi qua đường hầm. Trường đó mô tả nơi ứng dụng gửi truy vấn sau khi đường hầm lên. Nó không nói gì về cách máy khách tìm điểm cuối, và việc coi hai thứ đó là cùng một cài đặt chính là nơi sự nhầm lẫn bắt đầu.
Hai câu hỏi DNS, không phải một
Câu hỏi thứ nhất là: ứng dụng gửi truy vấn đi đâu khi đường hầm đã lên? Câu trả lời là một địa chỉ bộ phân giải bên trong đường hầm, tiếp cận được qua giao diện tun, và mang tính số theo cấu trúc.
Câu hỏi thứ hai là: máy khách tìm điểm cuối của chính nó thế nào trước khi đường hầm đó tồn tại? Việc tra cứu đó diễn ra bên ngoài đường hầm, trên mạng nền, trong tiến trình của máy khách. Nó có thể dùng tên, và nó phải dùng một bộ phân giải mà thiết bị tiếp cận được khi không có VPN.
| Stage | Who resolves | Path | Failure looks like |
|---|---|---|---|
| Endpoint lookup | The VPN app | Underlying network, protected socket | Never connects; no tunnel interface traffic |
| Peer authentication | Client and server | Tunnel transport | Connects then drops; certificate or key error |
| Private name lookup | Apps via the tunnel | Resolver inside the tun | Tunnel up, internal sites do not resolve |
Ba giai đoạn, ba triệu chứng khác nhau. Một thông báo lỗi duy nhất nói «không thể kết nối» gộp chúng lại làm một, và đó là lý do người ta bắt đầu sửa trường máy chủ DNS để chữa một vấn đề xảy ra trước khi trường đó từng được đọc.
Vì sao bootstrap có thể bế tắc
Always-on với chặn đang bật nghĩa là lưu lượng không ở trong VPN bị loại bỏ, kể cả lưu lượng của ứng dụng sở hữu VPN. Lối thoát là rõ ràng: ứng dụng gọi protect() trên một ổ cắm, điều này gắn nó với mạng nền để nó đi vòng qua đường hầm và được phép ra ngoài. Mọi máy khách VPN đều phải làm điều này cho phần truyền tải của mình, nếu không nó sẽ không bao giờ tới được máy chủ.
Giờ hãy xét một triển khai trong đó bộ phân giải duy nhất biết tên điểm cuối lại nằm bên trong đường hầm. Máy khách cần đường hầm để phân giải tên, và cần tên để dựng đường hầm. Đó là phụ thuộc vòng tròn thực sự, và không cấu hình máy khách nào giải quyết được. Đó là lỗi thiết kế, không phải lỗi phần mềm.
Thời điểm phơi bày cùng phụ thuộc đó ở dạng nhẹ hơn. Khi khởi động trước lần mở khóa đầu tiên, thiết bị có thể chưa có mạng dùng được; trên captive portal, mạng có nhưng chặn mọi thứ trừ cổng; khi chuyển từ Wi-Fi sang mạng di động, mạng nền của ổ cắm được bảo vệ thay đổi và máy khách phải nhận ra rồi phân giải lại. Mỗi điều đó là một sự kiện bootstrap, và mỗi điều đáng được kiểm thử có chủ đích thay vì phát hiện lúc 3 giờ sáng.
Vì sao ghim cứng câu trả lời không phải là giải pháp
Lối tắt hấp dẫn là phân giải tên một lần rồi dán địa chỉ thu được vào một trường số, hoặc mã hóa cứng nó trong một bản dựng tùy chỉnh. Nó có vẻ chạy được, và nó biến một cái tên thành một bức ảnh chụp. Khi nhà vận hành di chuyển điểm cuối — một lần di trú, một thay đổi anycast, một địa chỉ vùng mới — máy khách vẫn quay số cũ và không gì trong giao diện giải thích tại sao.
Bản ghi DNS có thời gian sống chính là để câu trả lời có thể thay đổi; bộ nhớ đệm được định nghĩa theo khoảng thời gian đó, không phải mãi mãi. Ghim cứng một câu trả lời vứt bỏ cơ chế khiến một cái tên tốt hơn một địa chỉ, trong khi vẫn giữ chi phí vận hành của việc đã dùng một cái tên.
Ghim cứng thường đi kèm một thói quen xấu thứ hai: nới lỏng kiểm tra danh tính vì kết nối giờ thất bại theo cách khác. Xác minh danh tính máy chủ không phải là một phần của vấn đề bootstrap, và làm yếu nó là đánh đổi một bất tiện DNS lấy rủi ro bị chặn nghe.
Những thiết kế sống sót qua khởi động lại
Cách bố trí bền vững không hào nhoáng. Hãy dùng một máy khách hiện thực đúng các ổ cắm được bảo vệ và phân giải điểm cuối của nó trên mạng nền, và cho nó một tên điểm cuối phân giải được công khai, hoặc qua một bộ phân giải tiếp cận được trước đường hầm. Hãy để chặn tiếp tục bật; tắt hẳn nó để DNS chạy được sẽ bỏ đi tính chất mà triển khai tồn tại vì nó.
Ở nơi điểm cuối phải giữ riêng tư, hãy cung cấp một đường bootstrap rõ ràng mà nền tảng có thể dùng — một bộ phân giải tiếp cận được khi không có đường hầm, hoặc một kết nối quản trị do nhà vận hành duy trì — và giữ ngoại lệ đó hẹp và thuộc về chính sách, không phải nút bật tắt của người dùng. Tài liệu Android VpnService là tham chiếu cho những gì nền tảng bảo đảm về bảo vệ và vòng đời, và tham chiếu VpnService.Builder xác nhận rằng trường DNS nhận địa chỉ dạng số.
Sau đó xác minh ba giai đoạn, theo thứ tự, trên một kết nối mới sau khi khởi động lại: tên điểm cuối phân giải được, đường hầm được thiết lập và đối tác được xác thực, và một tên riêng tư phân giải được qua bộ phân giải của đường hầm. Nếu giai đoạn đầu thất bại, không gì sau đó có thể chạy, và cách sửa thuộc về đường bootstrap — không bao giờ thuộc trường bộ phân giải.
- Việc phân giải điểm cuối diễn ra trong ứng dụng, bên ngoài đường hầm, trên một ổ cắm được bảo vệ.
- Trường DNS trong trình dựng dành cho ứng dụng bên trong đường hầm, không phải cho điểm cuối của chính máy khách.
- Một bộ phân giải chỉ tiếp cận được qua đường hầm là bế tắc, không phải khởi động chậm.
- Kiểm thử riêng điểm cuối, xác thực và tra cứu riêng tư sau khi khởi động lại.