Split tunneling dalam aplikasi VpnService rosak di beberapa tempat tertentu, dan pembaikannya berbeza bagi setiap satu. Klien hanya memaparkan satu destinasi yang gagal, jadi tugas pertama ialah menentukan sempadan mana yang anda langgar: laluan yang diterima builder, proxy yang tidak dapat anda sahkan, resolver yang hanya anda umumkan, atau senarai aplikasi yang platform gunakan bagi setiap pengguna. Sebab itulah saya menyimpan pemeriksaan empat langkah. Ia berjalan mengikut susunan di bawah dan berhenti pada kegagalan pertama.

Sahkan apa yang builder serahkan kepada platform

VpnService.Builder ialah senarai pengisytiharan. establish() mengembalikan ParcelFileDescriptor untuk antara muka maya, dan platform hanya menghantar trafik yang sepadan dengan awalan addAddress dan addRoute ke deskriptor itu; addDnsServer memberitahu klien resolver mana yang perlu ditanya. Destinasi di luar semua awalan yang anda tambah tidak pernah sampai ke aplikasi anda, apa pun janji antara muka. Fakta tunggal ini menjelaskan kebanyakan laporan split tunneling rosak sebelum kod diubah.

Log senarai alamat, laluan dan DNS yang dibina builder anda, kemudian bandingkannya dengan destinasi yang gagal. Satu /32 yang hilang untuk hos pengurusan jauh lebih biasa daripada terowong yang rosak. Jika senarai itu betul, teruskan; jika salah, baki senarai semak ialah usaha yang sia-sia.

excludeRoute hanya wujud sejak API 33

Pengecualian berasaskan destinasi ialah permintaan yang paling kerap menjadi bebenang sokongan. builder.excludeRoute(IpPrefix) hadir dalam API 33; sebelum itu satu-satunya penghampiran yang disokong ialah menambah laluan untuk segala-galanya kecuali awalan yang dikecualikan, yang bermakna anda perlu mengira sendiri awalan pelengkap. Kedua-dua panggilan bukan imej cermin: satu menolak daripada set laluan antara muka, satu lagi membina set itu dari kosong, dan peranti lama akan melontar atau senyap mengabaikan panggilan yang tidak dikenali. Bercabang pada Build.VERSION.SDK_INT dan uji kedua-dua laluan pada perkakasan sebenar.

Apabila mengira pelengkap, perhatikan penjajaran awalan. Pengecualian /24 di dalam laluan /16 memerlukan awalan penutup yang benar-benar menerangkan bakinya, bukan satu /8 yang cacat. Log senarai akhir dan sahkan hos yang dikecualikan masih diselesaikan melalui laluan di luar terowong.

Kelayakan proxy tidak dapat dinyatakan

setHttpProxy(ProxyInfo) menghalakan antara muka ke proxy HTTP atau SOCKS, dan URL PAC boleh memilih antara keduanya bagi setiap destinasi. ProxyInfo mahupun format PAC tidak membawa nama pengguna dan kata laluan, jadi proxy yang memerlukan pengesahan berada di luar API platform. Aplikasi yang memerlukannya biasanya membenamkan tindanan ruang pengguna, tun2socks atau enjin serupa, dan menjawab cabaran 407 sendiri.

Pilihan itu mempunyai kesan. Tindanan ruang pengguna hanya melihat trafik yang anda halakan kepadanya, jadi ia mesti hidup dalam sempadan deskriptor yang sama, dan ia mewarisi keperluan protect() yang sama untuk soket uplinknya sendiri. Tinggalkan protect() dan terowong menangkap pengangkutannya sendiri, yang muncul sebagai jabat tangan yang tersekat selepas paket pertama. Uji terhadap proxy yang menuntut kelayakan, kerana proxy terbuka lulus pada laluan platform dan tidak membuktikan apa-apa.

Senarai setiap aplikasi dan DNS juga pengisytiharan

Builder mempunyai addAllowedApplication dan addDisallowedApplication, dan kedua-duanya saling eksklusif: memanggil kedua-duanya melontar pengecualian. Walau apa pun senarai itu digunakan bagi setiap pengguna semasa persediaan antara muka, jadi aplikasi profil kerja ditadbir oleh terowong profil kerja dan bukan terowong anda. Apa yang tiada API berikan ialah kawalan atas keputusan aplikasi lain: anda tidak boleh menolak paket ke dalam terowong anda dari luar, dan anda tidak boleh menutup atau mengkonfigurasi semula VPN yang sudah aktif.

DNS mengikut corak yang sama. addDnsServer mengumumkan alamat resolver; ia tidak membenarkan aplikasi anda menjawab pertanyaan. Jika anda mahu menyelesaikan nama sendiri, jalankan resolver dan halakan alamatnya ke dalam terowong. Aplikasi yang menggunakan DoT atau DoH ke nama hos tetap boleh memintas alamat yang anda umumkan, jadi anggap penyelesaian nama sebagai usaha terbaik melainkan anda juga memintas laluan pertanyaan itu.

Manifest, always-on dan ujian empat langkah

Kelayakan diisytiharkan dalam manifest: BIND_VPN_SERVICE, penapis intent android.net.VpnService dan perkhidmatan latar depan jika terowong mesti bertahan di latar belakang. Always-on VPN turut menuntut onRevoke yang bersih, kerana sistem memanggilnya apabila pengguna menukar tetapan atau aplikasi lain mengambil alih kawalan.

Jalankan pemeriksaan mengikut urutan dan berhenti pada kegagalan pertama. Pertama, salurkan senarai alamat, laluan dan DNS yang diberikan kepada builder. Kedua, sahkan establish() mengembalikan deskriptor dan soket pengangkutan dilindungi. Ketiga, minta satu destinasi di dalam awalan yang disertakan dan satu di dalam awalan yang dikecualikan. Keempat, semak resolver mana yang benar-benar menjawab dengan menanyakan nama hos yang hanya resolver anda boleh selesaikan.

Jabat tangan yang selesai tidak membuktikan mana-mana langkah berikutnya. Setiap pemeriksaan mengasingkan satu lapisan, jadi kejayaan pada langkah kedua tidak berkata apa-apa tentang langkah keempat.

Rujukan VpnService.Builder menyenaraikan seluruh permukaan builder. Apa-apa yang anda perlukan di luarnya ialah API lain, aplikasi lain atau tindanan ruang pengguna anda sendiri, dan itu keputusan reka bentuk, bukan pepijat split tunnel.

Artikel berkaitan