Anda menambahkan sebuah domain ke daftar izin, kueri sampai ke aplikasi Anda, pencocok mengembalikan diizinkan, dan halaman itu tetap tidak pernah dimuat. Pada titik itu kebanyakan orang mulai menulis ulang pencocok dan menambahkan perbandingan wildcard. Menurut pengalaman saya pencocok biasanya benar, dan kegagalannya berada satu lapis lebih dalam: pada jawaban DNS yang Anda sintesiskan, pada rute yang Anda pasang, atau pada soket yang Anda pakai untuk meneruskan kueri. Daftar adalah bagian yang mudah; jalur paket adalah tempat daftar izin rusak.

Pencocok jarang menjadi penyebabnya

Hal pertama yang harus dipisahkan adalah terblokir dari rusak. Nama yang terblokir seharusnya gagal cepat dan terlihat, karena peramban menerima jawaban bahwa nama itu tidak ada lalu berhenti. Nama yang rusak macet, mencoba ulang lewat IPv6, beralih ke transport lain, dan meninggalkan Anda dengan indikator berputar. Jika Anda melihat indikator berputar, daftar izin Anda kemungkinan menjawab sesuatu yang tidak bisa ditindaklanjuti klien.

Rekaman A kosong adalah kesalahan klasik. Mengembalikan NOERROR dengan nol jawaban tampak seperti jawaban yang sah, sehingga resolver stub menerimanya, peramban mencoba lagi, mencoba AAAA, mencoba resolver lain, dan menyerah jauh kemudian. Kode jawaban 3, yaitu NXDOMAIN, dengan bagian pertanyaan diulang dan ID transaksi disalin, mengakhiri percakapan seketika. Pakailah untuk setiap nama yang sengaja Anda tolak.

IPv6 juga layak mendapat keputusan yang sama, bukan nilai bawaan. Jika Anda menjawab NXDOMAIN untuk A dan membiarkan AAAA lewat, klien bisa mencapai nama terblokir lewat IPv6 dan filter bocor. Sebagian implementasi menjawab kueri AAAA terblokir dengan alamat loopback agar koneksi langsung gagal alih-alih beralih ke cadangan. Pilih satu kebijakan, terapkan pada kedua jenis rekaman, dan catat keduanya.

Rute yang menangkap semuanya memiliki semuanya

Desain hanya DNS tidak pernah menambahkan addRoute("0.0.0.0", 0), jadi hanya kueri yang masuk ke antarmuka TUN dan semua hal lain tetap memakai jaringan di bawahnya. Itulah bentuk yang aman, dan itu juga menjelaskan mengapa sebagian daftar izin tampak berfungsi di Wi-Fi dan gagal di jaringan seluler.

Begitu ada rute bawaan, setiap aliran menjadi milik Anda. Paket TCP yang tiba di antarmuka dan tidak diteruskan maupun dijawab akan duduk di antrean sampai klien kehabisan waktu, dan tidak ada galat untuk dicatat karena tidak ada yang gagal. Saya pernah melihat seseorang menghabiskan sepanjang sore pada daftar izin yang rusak yang sebenarnya hanyalah penerus yang hilang untuk port 443. Catat protokol dan tujuan setiap paket yang Anda putuskan untuk dibuang.

Soket resolver harus keluar dari terowongan

Penerusan adalah tempat jebakan berikutnya. Resolver operator sering berada di alamat privat yang tidak dapat dijangkau terowongan, sehingga kueri yang Anda teruskan tidak ke mana-mana dan aplikasi melaporkan batas waktu baca. Kirim kueri yang disetujui ke resolver yang Anda tahu dapat dijangkau, dan berikan soket itu lebih dulu ke VpnService.protect(). Soket yang tidak dilindungi mengirim kueri kembali ke terowongan Anda sendiri, tempat ia tiba lagi di aplikasi dan berputar sampai batas waktu menyala.

Kegagalannya tampak identik dengan gangguan jaringan, dan itulah sebabnya ia bertahan begitu lama dalam laporan bug. Simpan penghitung untuk kueri yang dikirim dan balasan yang diterima: jika angka pertama naik dan angka kedua tetap nol, Anda sedang melihat soket, bukan daftar.

Ukuran dan checksum gagal tanpa pesan

Pembuangan diam-diam juga datang dari ukuran. Jawaban DNS dengan kumpulan jawaban besar, atau jabat tangan TCP dengan opsi berlimpah, bisa melebihi MTU jalur yang tidak pernah Anda tetapkan secara eksplisit; fragmennya hilang di hulu dan klien entah mencoba lagi dengan lebih kecil atau berhenti mencoba. Menetapkan MTU antarmuka ke 1280 adalah pilihan konservatif yang bertahan pada sebagian besar jalur seluler, dan bersikap eksplisit lebih baik daripada mewarisi nilai bawaan yang tidak pernah diukur siapa pun.

Jika Anda membangun paket sendiri, checksum adalah pembunuh diam-diam berikutnya. Checksum UDP yang dihitung pada pseudo-header yang melewatkan panjang UDP atau bidang protokol menghasilkan paket yang tampak terbentuk baik di sisi Anda dan dibuang penerima tanpa jejak. Bandingkan pseudo-header Anda dengan spesifikasi bidang demi bidang, dan cetak checksum yang dihitung untuk satu aliran yang dikenal saat Anda men-debug.

Apa yang tidak dilakukan VpnService untuk Anda

Ada dua batas yang perlu diketahui sebelum Anda merancang di sekitarnya. Tidak ada aplikasi biasa yang dapat memasang proksi seluruh sistem atau berkas PAC di luar Wi-Fi, dan bagian itu tidak berubah. Jalur per aplikasi berubah: sebelum API 29, VpnService.Builder sama sekali tidak dapat membawa proksi, dan sejak API 29 setHttpProxy(ProxyInfo.buildPacProxy(uri)) menyerahkan skrip PAC ke platform untuk dievaluasi bagi jaringan VPN. Evaluasi aturan di kode Anda sendiri saat menargetkan API lama atau saat model PAC tidak dapat menyatakan aturannya. UDP juga bukan gratis: peramban hanya mengirim TCP lewat proksi SOCKS, dan sebagian besar klien SOCKS5 tidak pernah mengimplementasikan UDP ASSOCIATE, jadi desain berbasis proksi membuang atau membocorkan UDP sementara TCP tampak sehat.

Batas kedua itulah sebabnya protokol berbasis UDP bisa bekerja di jaringan biasa dan gagal begitu VPN Anda tersambung. Jika terowongan diharapkan membawa UDP, penerus harus mengimplementasikan jalur penerusan untuk itu, bukan hanya jalur TCP dengan jenis soket lain.

Periksa dengan urutan ini

Kerjakan daftar secara berurutan dan berhenti di tahap pertama yang gagal, karena setiap pemeriksaan berikutnya hanya kebisingan sampai yang sebelumnya bertahan.

  1. Daftar rute yang terpasang dan pastikan apakah paket bukan DNS sama sekali masuk ke antarmuka TUN.
  2. Catat nama kueri, keputusan, dan kode jawaban untuk satu nama terblokir dan satu nama yang disetujui.
  3. Pastikan soket resolver terlindungi dan resolver yang dipilih menjawab dari dalam terowongan.
  4. Pastikan MTU antarmuka dan checksum satu balasan yang Anda bangun sendiri.
  5. Ulangi halaman yang sama di Wi-Fi dan di jaringan seluler, karena resolver operator dan MTU jalur berbeda.

Jika kelimanya bertahan dan halaman masih macet, tersangka berikutnya adalah penerus itu sendiri: bandingkan permintaan yang tertangkap dengan balasan yang tertangkap dan cari jumlah bita yang hilang atau soket setengah tertutup. Referensi VpnService.Builder mencakup kontrak rute, DNS, dan MTU, dan protect() adalah panggilan VpnService terpisah, bukan opsi builder; antarmuka tersambung hanya berarti kontrak pertama terpenuhi.

Artikel terkait