Không có gì trong VpnService tự chặn lưu lượng. Nó yêu cầu hệ thống một giao diện tun, trao cho giao diện đó một tập địa chỉ và tuyến, và từ thời điểm đó nhân sao chép mọi gói khớp với các tuyến đó vào một bộ mô tả tệp mà ứng dụng có thể đọc. Mã của ứng dụng không bao giờ thấy những gói mà các tuyến không chọn, nên phạm vi của một đường hầm là câu hỏi về bảng định tuyến trước khi là câu hỏi về lập trình. Đó là lý do cùng một cách hiện thực dịch vụ có thể nuốt mọi luồng trên một điện thoại và chỉ một phần trên điện thoại khác, và đó là lý do thêm một tuyến đôi khi sửa được đường hầm trông như đã hỏng. Bạn nhận được đúng những gì đã khai báo, trừ đi mọi thứ mà trình tạo đã lặng lẽ từ chối.

Các tuyến quyết định gói nào đến

Builder.addRoute(prefix, prefixLength) cài một tiền tố vào bảng định tuyến của mạng VPN. Hệ thống coi mạng đó là mặc định cho các ứng dụng trong phạm vi, nên các mục của nó được tra trước tuyến mặc định của mạng vật lý và một tiền tố khớp là đủ để chuyển hướng một luồng. Vì thế một tuyến cho 0.0.0.0/0 lấy toàn bộ IPv4, gồm máy in, mục tiêu cast và trang quản trị của router.

Những khách hàng muốn độ phủ đó mà không xoá mục mặc định vật lý thì dùng cặp 0.0.0.0/1 và 128.0.0.0/1 thay vào đó. Hai tuyến cụ thể hơn thắng một tuyến mặc định, cùng nhau chúng phủ toàn bộ không gian địa chỉ, và mục mặc định của chính điện thoại vẫn nằm trong bảng cho các socket còn gắn với mạng vật lý.

Địa chỉ và mục DNS đến từ cùng trình tạo và trả lời một câu hỏi khác. addAddress cho giao diện một địa chỉ với độ dài tiền tố, và addDnsServer cài một bộ phân giải mà các ứng dụng trong phạm vi sẽ hỏi qua giao diện. Cả hai họ đều có thể nằm trên một giao diện, nên một tập tuyến chỉ IPv4 bên cạnh địa chỉ IPv6 là cấu hình đọc đúng mà vẫn rò. Nếu bạn định tuyến một họ mà giao diện không có địa chỉ, nhân không có địa chỉ nguồn cho những gói đó và chúng không bao giờ xuất hiện ở bộ mô tả.

establish() trả về gì

establish() trả về một ParcelFileDescriptor, hoặc null khi ứng dụng không được cấp quyền. Null là trạng thái đồng ý chứ không phải lỗi mạng: VpnService.prepare() hẳn đã trả về null, hoặc người dùng phải đã chấp thuận hộp thoại hệ thống trước lời gọi. Sự đồng ý có thể bị thu hồi khi dịch vụ đang chạy, và giao diện đóng lại dưới chân bạn mà không có lời gọi lại nào vào vòng đọc của bạn.

Bộ mô tả không chặn trừ khi bạn nói khác, nên một lần đọc trả về ngay mà không có dữ liệu thay vì đỗ luồng lại. Một vòng viết cho socket chặn sẽ đốt một lõi, và một vòng coi lần đọc rỗng là chí mạng sẽ xé đường hầm trong một giây nhàn rỗi. Builder.setBlocking(true) đổi hành vi đó, và cái giá là một luồng chờ bên trong lần đọc.

Các đối số tuyến và địa chỉ được kiểm là giá trị LinkAddress, và các đích multicast như 224.0.0.0/4 bị từ chối thẳng. Giao diện tun điểm-điểm cũng không có miền quảng bá, nên việc khám phá multicast qua nó cần một thiết kế khác chứ không phải thêm một tuyến. Danh sách cần kiểm là VpnService.Builder, trước khi bạn kết luận rằng một lời gọi đã bị bỏ qua.

Phạm vi theo ứng dụng thu hẹp tập hợp, không thu hẹp đường hầm

Từ API 21 trình tạo chấp nhận addAllowedApplication và addDisallowedApplication, và hai danh sách loại trừ nhau trong một trình tạo. Danh sách cho phép làm đường hầm tồn tại cho những gói đó trong khi mọi thứ khác giữ mạng vật lý; danh sách cấm bắt mọi thứ trừ những gói được nêu tên, điều mà một khách hàng cung cấp như đường hầm tách rời. Trước API 21 không có cơ chế nền tảng nào cả, và hành vi theo ứng dụng đến từ các khách hàng bên thứ ba lọc theo UID trong bộ chuyển tiếp của riêng họ. Sự khác biệt này quan trọng khi gỡ lỗi, vì một đường hầm theo ứng dụng với danh sách cho phép một gói hầu như không tạo lưu lượng và đó là hành vi đúng, không phải tuyến hỏng.

Dù phạm vi là gì, socket mà ứng dụng của bạn mở tới máy chủ VPN không được đi qua đường hầm mà nó đang dựng. VpnService.protect(socket) gắn socket đó vào mạng bên dưới để các gói của nó bỏ qua thiết bị tun. Nếu bỏ qua lời gọi đó, cú bắt tay sẽ bị nuốt bởi chính giao diện lẽ ra phải dựng nó lên.

VpnService.setUnderlyingNetworks khép vòng bằng cách nói cho hệ thống biết mạng vật lý nào mang đường hầm. Giá trị đó quyết định cách VPN báo cáo kết nối cho các ứng dụng khác, và một giá trị null hoặc cũ là nguyên nhân thường gặp của một đường hầm đã kết nối mà phần còn lại của điện thoại coi là ngoại tuyến. Cập nhật nó khi mạng bên dưới thay đổi, không chỉ lúc khởi động.

Tổng kiểm và MTU: nơi một tuyến đúng vẫn thất bại

Khi các gói đã đến, hai chi tiết ở mức gói quyết định liệu có gì hoạt động từ đầu đến cuối. Thứ nhất là địa chỉ nguồn: với nhiều địa chỉ giao diện, nhân có thể phát ra các gói mang địa chỉ đầu tiên, nên một bộ chuyển tiếp viết lại tiêu đề phải sửa địa chỉ và tổng kiểm bao lấy nó.

Thứ hai là phạm vi của tổng kiểm. Khi ứng dụng tự dựng gói TCP hoặc UDP, tổng kiểm bao một tiêu đề giả chứa địa chỉ nguồn, địa chỉ đích, số giao thức và độ dài vận chuyển, và bỏ sót bất kỳ mục nào trong số đó sẽ cho ra những gói đến rồi bị bỏ. Lỗi đó trông như hết thời gian sau một phản hồi không bao giờ tới, điều này đưa phần lớn người ta quay lại với các tuyến. setMtu đặt MTU của giao diện, và mỗi lần đọc trả về đúng một gói IP trọn vẹn, nên một bộ đệm viết cho dòng byte sẽ chia nhỏ việc phân tích của bạn chứ không phải gói.

Một vòng kiểm chứng tách các tầng

Để tìm nơi phạm vi đi sai, hãy thử các tầng theo thứ tự. Hỏi thiết bị xem mạng VPN thực sự giữ những tuyến nào, rồi kiểm xem luồng tới một địa chỉ đã biết có hiện ra như một lần đọc ở bộ mô tả không, rồi kiểm xem gói mà bộ chuyển tiếp của bạn phát ra có được định dạng tốt không. Một vấn đề tuyến không cho thấy gì ở bộ mô tả, trong khi một vấn đề tổng kiểm cho thấy một gói đến rồi biến mất.

Nếu không có gì đến bộ mô tả, kẻ tình nghi là tập tuyến chứ không phải bộ đọc: xác nhận các tiền tố, xác nhận có một địa chỉ trong cùng họ và xác nhận ứng dụng nằm trong phạm vi bạn đã đặt. Nếu các gói đến bộ mô tả nhưng không có gì trở về, hãy kiểm tra protect() và giá trị của mạng bên dưới trước khi chạm lại vào một tuyến. Nếu phía xa báo cáo các gói bị hỏng, tổng kiểm và MTU là những nơi cần nhìn. Một phép thử cho mỗi tầng tiết kiệm một buổi chiều phỏng đoán.

Bài viết liên quan