Dua gejala muncul dalam gelung VpnService yang sama dan kedua-duanya disalahkan pada perkara yang sama: pembaca yang tidak pernah kembali, dan tulisan yang gagal dengan ENOBUFS. Ini bukan variasi satu pepijat. Bacaan tersekat ialah perselisihan tentang kawalan aliran dengan rakan; tulisan gagal ialah paket yang tidak akan diterima oleh antara muka. Jika anda menganggapnya satu masalah, anda akan menghabiskan sehari menala penimbal yang tidak pernah terlibat. Pembahagian di bawah ialah cara saya memutuskan separuh gelung mana yang diinstrumentasi dahulu.

Satu gelung, dua titik kegagalan bebas

Perkhidmatan anda membaca paket IP daripada deskriptor fail TUN, memeriksanya dan menulis balasan kembali ke deskriptor yang sama. Semua yang rosak di laluan itu muncul pada salah satu daripada dua panggilan tersebut, sebab itu kedua-duanya dilaporkan sebagai terowong rosak. Panggilan itu mempunyai kontrak berbeza. Bacaan menunggu kernel menyerahkan paket kepada anda, dan tulisan menyerahkan kepada kernel paket yang boleh ditolaknya.

Bacaan ialah separuh yang mudah untuk difikirkan. Bacaan yang tidak memulangkan apa-apa sama ada menunggu trafik yang tidak pernah tiba atau menunggu kerana rakan berhenti menghantar.

Bacaan tersekat ialah perselisihan kawalan aliran

Membaca peranti TUN menyekat sehingga paket tersedia. Itu tingkah laku yang direka, dan sebab itulah benang yang tersangkut dalam read kelihatan normal pada pautan terbiar. Ia menjadi tergantung apabila tindanan TCP anda sendiri terus menerima data daripada aplikasi tempatan tetapi tidak pernah mengumumkan tetingkap yang cukup untuk rakan jauh menghantar lebih banyak. Rakan mengisi tetingkap yang anda umumkan, menunggu ACK dan kemas kini tetingkap, kemudian berhenti. Pembaca anda kemudian tidak mempunyai apa-apa untuk dipulangkan, dan aplikasi melihat sambungan yang terbuka tetapi senyap.

Punca biasa ialah tindanan yang menulis ke soket tanpa menjejaki tetingkap yang diumumkan, dan satu lagi yang terlupa menghantar kemas kini tetingkap selepas mengosongkan penimbalnya. Dari luar kedua-duanya kelihatan sama: bait keluar, tiada apa kembali, tiada ralat dilemparkan. Menyekat benang bacaan pada penghuraian, penyelesaian DNS atau I/O cakera menghasilkan bentuk gejala yang sama atas sebab tidak berkaitan, jadi pastikan benang itu benar-benar dalam read sebelum menyalahkan kawalan aliran.

Semak baris gilir hantar rakan dan tetingkap yang terakhir dilihatnya. Jika rakan menahan data kerana tetingkap anda sifar, pembetulan ada di laluan ACK anda, bukan dalam bacaan TUN.

ENOBUFS ialah masalah saiz, bukan kekurangan penimbal

Tulisan yang memulangkan ENOBUFS pada antara muka TUN biasanya menolak panjang paket. Antara muka mempunyai MTU, paket yang lebih besar tidak boleh dimasukkan ke dalam baris gilir, dan mencuba semula paket yang sama gagal dengan cara yang sama setiap kali. Determinisme itu ialah petunjuknya. Kekurangan penimbal sebenar hilang apabila tekanan menurun, manakala penolakan saiz tidak peduli berapa lama anda menunggu.

TCP mempunyai mekanisme khusus untuk ini, dan itulah langkah yang orang langkau: pengapit MSS. Apabila anda mensintesis segmen dalam ruang pengguna, anda memilih saiz muatan, dan mengambilnya daripada MTU antara muka tempatan dan bukannya MTU terowong mengeluarkan segmen yang terowong tidak dapat membawa. Hadkan kepada yang lebih kecil antara kedua-duanya. Pengapit hanya meliputi TCP, jadi datagram UDP yang terlalu besar mesti difragmentasi atau digugurkan oleh kod anda.

Log panjang setiap paket yang anda tulis semasa menyahpepijat. Panjang yang gagal ialah jawapannya, dan ia tidak akan berubah antara percubaan.

Tiga ukuran yang memisahkan kes

Anda tidak memerlukan penyahpepijat untuk mana-mana daripada dua kegagalan itu. Tiga pemerhatian cukup untuk mengarahkan anda ke bahagian yang betul, dan ia mengambil masa lebih singkat daripada bina semula.

What you seeWhere to look
Reader parked, peer send queue empty, last advertised window zeroWindow updates in your ACK path
Write fails on one length and succeeds on a smaller oneMSS clamp and tunnel MTU
Both directions look fine, app still sees no dataProtected socket and routing loop

Jika baris ketiga sepadan, gelung itu sendiri baik dan masalahnya terletak di tempat terowong tidak dapat melihatnya: soket pengangkutan tidak dilindungi yang membawa trafik VPN anda sendiri kembali ke dalam terowong, yang biasanya muncul sebagai sambungan yang berjaya kemudian tidak menyampaikan apa-apa.

Baiki saluran paip yang menjadi sandaran kedua-dua laluan

Tiada gejala yang layak dikejar sehingga antara muka dibina dengan betul. Panggilan builder yang penting ialah alamat, laluan, MTU dan persetujuan, dalam susunan itu:

Builder()
  .addAddress(10.8.0.2, 32)
  .addRoute(0.0.0.0, 0)
  .setMtu(1400)
  .establish()

Tetapkan MTU kepada nilai sebenar terowong dan bukannya membiarkannya pada nilai yang digunakan oleh contoh. Semua yang anda tulis kemudiannya terhad oleh nombor itu, dan ketidakpadanan antara MTU yang anda tetapkan dan MSS yang anda hadkan ialah cara paling biasa untuk memperkenalkan semula kegagalan tulisan selepas pembetulan. Kemudian lindungi soket yang membawa trafik ke pelayan VPN itu sendiri. Tanpa protect, paket itu dihalakan semula ke terowong anda sendiri dan sambungan tidak pernah selesai, yang kelihatan seperti bacaan tersekat tetapi sebenarnya gelung penghalaan.

Persetujuan tidak boleh dipintas. Perkhidmatan yang dimulakan tanpa prepare memulangkan null tidak mendapat antara muka, dan establish memulangkan null dan bukannya melontar, jadi semak deskriptor sebelum memulakan gelung. Rujukan VpnService ialah tempat untuk mengesahkan kontrak builder dan bukannya menyalin contoh.

Sahkan satu arah pada satu masa

Hantar gema UDP melalui terowong dan perhatikan panjang paket sebelum menyentuh TCP. Kemudian buka jabat tangan dan sahkan segmen kekal di bawah MSS yang anda kira. Kira paket dan bukan sambungan, supaya tersekat muncul sebagai jurang dalam pembilang dan bukannya soket tergantung. Jika bacaan berhenti selepas ledakan tulisan, tetingkap ialah suspek; jika tulisan gagal serta-merta, panjangnya.

Kemudian but semula peranti dan ulang sekali, kerana VpnService yang hanya berfungsi sehingga perubahan rangkaian pertama ialah masalah penghalaan, bukan kawalan aliran.

Artikel berkaitan