Tidak ada apa pun di VpnService yang menyadap lalu lintas dengan sendirinya. Ia meminta antarmuka tun dari sistem, menyerahkan sekumpulan alamat dan rute kepada antarmuka itu, dan sejak saat itu kernel menyalin setiap paket yang cocok dengan rute tersebut ke deskriptor berkas yang dapat dibaca aplikasi. Kode aplikasi tidak pernah melihat paket yang tidak dipilih rute, jadi cakupan terowongan adalah pertanyaan tabel perutean sebelum menjadi pertanyaan pemrograman. Itulah sebabnya implementasi layanan yang sama dapat menelan setiap aliran di satu ponsel dan hanya sebagian di ponsel lain, dan itulah sebabnya menambahkan rute kadang memperbaiki terowongan yang tampak rusak. Yang Anda dapatkan adalah yang Anda nyatakan, dikurangi apa pun yang ditolak pembangun secara diam-diam.

Rute menentukan paket mana yang tiba

Builder.addRoute(prefix, prefixLength) memasang prefiks ke tabel perutean jaringan VPN. Sistem memperlakukan jaringan itu sebagai bawaan bagi aplikasi dalam cakupan, sehingga entrinya diperiksa sebelum rute bawaan jaringan fisik dan prefiks yang cocok sudah cukup untuk mengalihkan aliran. Karena itu rute untuk 0.0.0.0/0 mengambil IPv4 sepenuhnya, termasuk printer, target cast, dan halaman admin router.

Klien yang menginginkan cakupan itu tanpa menghapus entri bawaan fisik memakai pasangan 0.0.0.0/1 dan 128.0.0.0/1 sebagai gantinya. Dua rute yang lebih spesifik mengalahkan rute bawaan, bersama-sama keduanya mencakup seluruh ruang alamat, dan entri bawaan ponsel itu sendiri tetap ada di tabel untuk soket yang masih terikat ke jaringan fisik.

Alamat dan entri DNS berasal dari pembangun yang sama dan menjawab pertanyaan berbeda. addAddress memberi antarmuka alamat dengan panjang prefiks, dan addDnsServer memasang penyelesai yang akan ditanyakan aplikasi dalam cakupan melalui antarmuka. Kedua keluarga dapat berada pada satu antarmuka, jadi kumpulan rute hanya IPv4 di samping alamat IPv6 adalah konfigurasi yang terbaca benar dan tetap bocor. Jika Anda merutekan keluarga yang tidak memiliki alamat pada antarmuka, kernel tidak punya alamat sumber untuk paket itu dan paket tersebut tidak pernah muncul di deskriptor.

Apa yang dikembalikan establish()

establish() mengembalikan ParcelFileDescriptor, atau null ketika aplikasi tidak diotorisasi. Null adalah keadaan persetujuan, bukan galat jaringan: VpnService.prepare() harus sudah mengembalikan null, atau pengguna harus sudah menyetujui dialog sistem sebelum panggilan. Persetujuan dapat dicabut saat layanan berjalan, dan antarmuka tertutup di bawah Anda tanpa panggilan balik ke loop baca Anda.

Deskriptor tidak memblokir kecuali Anda menyatakan sebaliknya, jadi pembacaan kembali segera tanpa data alih-alih memarkir thread. Loop yang ditulis untuk soket memblokir membakar satu inti, dan loop yang menganggap pembacaan kosong sebagai fatal merobek terowongan dalam satu detik menganggur. Builder.setBlocking(true) mengubah perilaku itu, dan harganya adalah thread yang menunggu di dalam pembacaan.

Argumen rute dan alamat divalidasi sebagai nilai LinkAddress, dan tujuan multicast seperti 224.0.0.0/4 ditolak mentah-mentah. Antarmuka tun titik-ke-titik juga tidak memiliki domain siaran, jadi penemuan multicast melaluinya memerlukan desain lain, bukan satu rute lagi. Referensi VpnService.Builder adalah daftar yang perlu diperiksa sebelum Anda menyimpulkan bahwa suatu panggilan diabaikan.

Cakupan per aplikasi mempersempit himpunan, bukan terowongan

Sejak API 21 pembangun menerima addAllowedApplication dan addDisallowedApplication, dan kedua daftar saling eksklusif dalam satu pembangun. Daftar izin membuat terowongan ada untuk paket tersebut sementara semua yang lain mempertahankan jaringan fisik; daftar larangan menangkap semua kecuali paket yang disebut, yang ditawarkan klien sebagai terowongan terpisah. Sebelum API 21 tidak ada mekanisme platform sama sekali, dan perilaku per aplikasi datang dari klien pihak ketiga yang menyaring menurut UID di dalam penerus mereka sendiri. Perbedaannya penting saat men-debug, karena terowongan per aplikasi dengan daftar izin satu paket hampir tidak menghasilkan lalu lintas dan itu perilaku yang benar, bukan rute yang rusak.

Betapapun cakupannya, soket yang dibuka aplikasi Anda ke server VPN tidak boleh berjalan melalui terowongan yang sedang dibangunnya. VpnService.protect(socket) mengikat soket itu ke jaringan yang mendasari agar paketnya melewati perangkat tun. Jika Anda melewati panggilan itu, jabat tangan ditelan oleh antarmuka yang seharusnya menaikkannya.

VpnService.setUnderlyingNetworks menutup lingkaran dengan memberi tahu sistem jaringan fisik mana yang membawa terowongan. Nilai itu menentukan bagaimana VPN melaporkan konektivitas ke aplikasi lain, dan nilai null atau basi adalah penyebab umum terowongan tersambung yang dianggap ponsel lainnya sebagai luring. Perbarui saat jaringan yang mendasari berubah, bukan hanya saat mulai.

Checksum dan MTU: tempat rute yang benar tetap gagal

Setelah paket tiba, dua detail pada tingkat paket menentukan apakah ada yang bekerja dari ujung ke ujung. Yang pertama adalah alamat sumber: dengan beberapa alamat antarmuka kernel dapat mengirim paket yang membawa yang pertama, jadi penerus yang menulis ulang tajuk harus memperbaiki alamat dan checksum yang menutupinya.

Yang kedua adalah cakupan checksum. Saat aplikasi membangun paket TCP atau UDP sendiri, checksum mencakup pseudo-tajuk yang memuat alamat sumber, alamat tujuan, nomor protokol, dan panjang transportasi, dan menghilangkan salah satunya menghasilkan paket yang tiba lalu dibuang. Kegagalan itu tampak seperti batas waktu setelah balasan yang tidak pernah datang, yang mengirim sebagian besar orang kembali ke rute. setMtu menetapkan MTU antarmuka, dan setiap pembacaan mengembalikan tepat satu paket IP utuh, jadi buffer yang ditulis untuk aliran byte akan memecah penguraian Anda, bukan paketnya.

Satu putaran verifikasi yang memisahkan lapisan

Untuk menemukan di mana cakupan salah, uji lapisan secara berurutan. Tanyakan kepada perangkat rute mana yang sebenarnya dipegang jaringan VPN, lalu periksa apakah aliran ke alamat yang dikenal muncul sebagai pembacaan di deskriptor, lalu periksa apakah paket yang dikirim penerus Anda terbentuk dengan baik. Masalah rute tidak menunjukkan apa pun di deskriptor, sedangkan masalah checksum menunjukkan paket yang tiba dan menghilang.

Jika tidak ada yang mencapai deskriptor, tersangkanya adalah kumpulan rute dan bukan pembaca: pastikan prefiksnya, pastikan ada alamat dalam keluarga yang sama, dan pastikan aplikasi berada di dalam cakupan yang Anda tetapkan. Jika paket mencapai deskriptor tetapi tidak ada yang kembali, periksa protect() dan nilai jaringan yang mendasari sebelum menyentuh rute lagi. Jika sisi jauh melaporkan paket cacat, checksum dan MTU adalah tempat untuk melihat. Satu penyelidikan per lapisan menghemat satu sore menebak-nebak.

Artikel terkait