Tunnel naik, ikon kunci muncul, dan setiap permintaan dalam pelayar masih tamat masa. Dalam aplikasi VpnService gabungan itu biasanya bermaksud gelung baca masih hidup dan separuh keluaran rosak, bukan pelayan menolak jabat tangan. Android sudah mencipta antara muka, memindahkan trafik aplikasi ke dalamnya dan menyerahkan deskriptor fail kepada proses anda. Semua selepas deskriptor itu ialah kod anda, dan satu panggilan yang hilang cukup untuk menelan seluruh aliran.

Apa yang sistem beri dan apa yang tidak

establish() mengembalikan ParcelFileDescriptor untuk antara muka tun. Sistem menulis paket IP keluar ke dalamnya dan menjangka proses anda membacanya, memutuskan ke mana ia pergi dan menghantarnya melalui soket biasa. Tiada pemajuan kernel di bawahnya, jadi apabila tiada siapa membaca, paket digugurkan dan pembilang antara muka tidak pernah bergerak.

Mulakan dengan mengira bukan meneka. Tingkatkan pembilang pada setiap bacaan berjaya dan catat destinasi serta protokol beberapa paket pertama. Jika pembilang kekal sifar semasa trafik dijana, kerosakan terletak di atas kod pemajuan anda, yang menyempitkan carian kepada konfigurasi builder dan mod baca. Jika pembilang bergerak dan pelayar masih gagal, kerosakan ada pada laluan hantar atau laluan balik.

Bacaan menyekat menentukan sama ada gelung bergerak

setBlocking(true) meletakkan deskriptor dalam mod menyekat dan wujud sejak API 21. Pada keluaran lama penyelesaiannya ialah pembantu JNI kecil yang membersihkan O_NONBLOCK dengan fcntl pada deskriptor mentah. Mod ini penting kerana ia menentukan apa yang boleh dilakukan oleh bacaan tanpa paket menunggu.

Dalam mod tidak menyekat bacaan itu kembali serta-merta dengan nilai negatif, dan gelung yang mengabaikan hasilnya memusingkan teras tanpa memindahkan sebarang trafik. Dalam mod menyekat bacaan menunggu, iaitu yang dikehendaki oleh benang pemajuan, tetapi benang itu kemudian tidak boleh diganggu lagi. Menutup deskriptor ialah cara disokong untuk membuat bacaan gagal supaya gelung boleh keluar. Membunuh proses atau mengganggu benang boleh meninggalkan permulaan seterusnya dengan deskriptor yang tidak lagi sepadan dengan antara muka.

Baca satu paket setiap panggilan ke dalam penimbal bersaiz MTU antara muka, dan anggap sifar atau pulangan negatif sebagai ralat, bukan paket kosong.

protect() sebelum penghantaran pertama, bukan selepasnya

Setiap soket yang membawa paket terkapsul mesti dilindungi dahulu. Soket tidak dilindungi mematuhi peraturan penghalaan yang baru anda pasang, jadi paketnya kembali ke dalam tunnel dan gelung baca anda sendiri mengambilnya semula. Tunnel kemudian memajukan outputnya sendiri tanpa henti, dan dari luar ia kelihatan seperti sambungan yang terbuka dan tidak pernah menjawab.

Urutannya protect, kemudian connect atau bind, kemudian send. Memanggil protect selepas connect boleh meninggalkan keputusan laluan terdahulu, jadi soket terus menggunakan laluan salah walaupun panggilan mengembalikan true. Periksa boolean yang dikembalikan dan gagal dengan lantang apabila false, bukan memasuki penghantaran yang tidak mungkin berfungsi.

Ralat kebenaran daripada sendto pada soket yang tidak pernah menyentuh protect() ialah tanda biasa kesilapan ini.

Contoh UDP tidak membawa HTTPS

Contoh pemajuan yang disalin kebanyakan tutorial hanya mengendalikan UDP. TCP memerlukan jabat tangan, nombor jujukan, pengakuan dan penghantaran semula, dan gelung yang menyalin muatan antara deskriptor tun dan soket tidak menyediakan satu pun. Itulah sebabnya pertanyaan DNS melalui UDP boleh lepas sementara setiap permintaan HTTPS tersekat. Jalankan tindanan TCP dalam ruang pengguna atau serahkan sambungan kepada proksi tempatan yang menamatkan TCP pada peranti dan memajukan aliran.

Uji pemisahan sebelum menulis semula apa-apa: hantar satu pertanyaan UDP dan buka satu sambungan TCP ke hos yang sama. Jika laluan UDP berfungsi dan laluan TCP tersekat pada SYN pertama, masalahnya ialah kod pemajuan bukan pelayan. Perbandingan tunggal itu menjimatkan banyak masa membaca log pelayan yang tidak mengandungi apa-apa berguna.

Senarai laluan dan penapis setiap aplikasi mengehadkan apa yang anda lihat

addAddress, addRoute dan addDns menentukan apa yang sistem hantar ke dalam tunnel. Destinasi di luar senarai laluan tidak pernah sampai ke deskriptor anda, jadi berapa banyak logik pemajuan pun tidak akan membaikinya. Catat panggilan builder yang anda buat dan bandingkan dengan alamat yang benar-benar cuba dicapai oleh aplikasi.

Pemilihan setiap aplikasi mempunyai hadnya sendiri: addAllowedApplication dan addDisallowedApplication memerlukan API 21, dan pada keluaran lama kaedah itu tiada sama sekali. Reka bentuk yang menapis mengikut paket tidak boleh berjalan di sana.

Pembinaan semula meninggalkan deskriptor usang

Memanggil establish() semula mengembalikan deskriptor baharu dan menutup antara muka sebelumnya. Deskriptor lama kini tidak sah, jadi benang yang masih tersekat padanya menerima ralat, dan soket yang dicipta untuk laluan lama mungkin perlu diganti. onRevoke ialah panggilan balik untuk tunnel yang diambil oleh pengguna atau sistem. Menyimpan kitaran hayat pada satu pemilik, yang menghentikan pembaca sebelum membina semula, mengelakkan kebanyakan keadaan bersambung-tetapi-mati.

Baca setiap ralat mengikut langkahnya. Set semula sambungan daripada recvfrom bermaksud hujung jauh menutup semasa kod anda masih membaca. Ralat alamat buruk menunjuk kepada penghuraian pengepala atau pepijat offset, bukan rangkaian.

Urutan kerja: mod menyekat hidup, satu paket setiap bacaan, pengepala dihuraikan, soket dilindungi, muatan dihantar, penutupan bersih semasa penyerahan dan senarai laluan yang meliputi destinasi.

Artikel berkaitan