Android VpnService: TUN уншилт гацах ба ENOBUFS бичих алдаанууд
Хэзээ ч буцаж ирдэггүй уншилт ба ENOBUFS-тэй бүтэлгүйтдэг бичилт нь эсрэг шалтгаантай. Залруулгыг сонгохын тулд зарласан цонх болон пакетын уртыг хэмжинэ.
Нэг VpnService давталтад хоёр шинж тэмдэг гарч, хоёуланд нь нэг зүйлийг буруутгадаг: хэзээ ч буцаж ирдэггүй уншигч, ENOBUFS-тэй бүтэлгүйтдэг бичилт. Эдгээр нь нэг алдааны хувилбар биш. Гатсан уншилт нь хамтрагчтай урсгалын хяналтын талаарх санал зөрөлдөөн; бүтэлгүйтсэн бичилт нь интерфэйс хүлээж авахгүй пакет юм. Хэрэв тэдгээрийг нэг асуудал гэж үзвэл хэзээ ч оролцоогүй буферуудыг тохируулахад нэг өдөр зарцуулна. Доорх хуваалт нь давталтын аль хагасыг эхлээд хэмжихийг би хэрхэн шийддэг тухай юм.
Нэг давталт, хоёр бие даасан эвдрэлийн цэг
Таны үйлчилгээ TUN файлын дескриптороос IP пакет уншиж, шалгаад мөн тэр дескрипторт хариу бичдэг. Энэ замд эвдэрсэн бүхэн тэр хоёр дуудлагын нэгэнд илэрдэг, тиймээс хоёуланг нь туннель эвдэрсэн гэж мэдээлдэг. Дуудлагуудын гэрээ өөр. Уншилт цөм танд пакет өгөхийг хүлээдэг, бичилт нь цөмд татгалзах эрхтэй пакетыг өгдөг.
Уншилтууд бол бодоход хялбар хагас. Юу ч буцаадаггүй уншилт нь хэзээ ч ирэхгүй урсгалыг хүлээж байна, эсвэл хамтрагч илгээхээ болилсон учраас хүлээж байна.
Гатсан уншилт бол урсгалын хяналтын санал зөрөлдөөн
TUN төхөөрөмжийг унших нь пакет бэлэн болтол блоклодог. Энэ бол зохион бүтээсэн зан төлөв бөгөөд идэвхгүй холбоос дээр read дотор зогссон урсгал хэвийн харагддаг шалтгаан нь энэ. Хэрэв таны өөрийн TCP стек локал аппаас өгөгдөл хүлээж авахаа үргэлжлүүлэх боловч алсын хамтрагч илүү их илгээхэд хангалттай цонхыг хэзээ ч зарлахгүй бол энэ нь гацалт болно. Хамтрагч таны зарласан цонхыг дүүргэж, ACK болон цонхны шинэчлэлтийг хүлээгээд зогсдог. Тэгэхэд таны уншигчид буцаах зүйл байхгүй, апп нь нээлттэй боловч чимээгүй холболтыг хардаг.
Түгээмэл шалтгаан нь зарласан цонхыг хяналтгүйгээр сокет руу бичдэг стек, мөн буфераа хоосон болгосны дараа цонхны шинэчлэлт илгээхээ мартдаг стек юм. Гаднаас харахад хоёулаа ижил: байтууд гардаг, юу ч буцаж ирдэггүй, алдаа гардаггүй. Унших урсгалыг задлан шинжлэх, DNS шийдвэрлэх эсвэл дискний I/O үед блоклох нь хамааралгүй шалтгаанаар ижил хэлбэрийн шинж тэмдэг үүсгэдэг, тиймээс урсгалын хяналтыг буруутгахын өмнө урсгал үнэхээр read дотор байгаа эсэхийг баталгаажуулна уу.
Хамтрагчийн илгээх дараалал болон түүний хамгийн сүүлд харсан цонхыг шалгана уу. Хамтрагч таны цонх тэг байгаа учраас өгөгдөл бариад байгаа бол залруулга нь таны ACK замд байна, TUN уншилтад биш.
ENOBUFS бол хэмжээний асуудал, буферийн дутагдал биш
TUN интерфэйс дээр ENOBUFS буцаадаг бичилт нь ихэвчлэн пакетын уртыг татгалздаг. Интерфэйс MTU-тай, түүнээс том пакетыг дараалалд хийх боломжгүй, мөн ижил пакетыг дахин оролдоход бүр удаа ижилхэн бүтэлгүйтдэг. Энэ детерминизм нь дохио юм. Жинхэнэ буферийн дутагдал даралт буурахад арилдаг бол хэмжээний татгалзал таны хүлээх хугацааг тоохгүй.
TCP-д яг үүнд зориулсан механизм байдаг бөгөөд энэ нь хүмүүсийн алгасдаг алхам: MSS хязгаарлалт. Хэрэглэгчийн орон зайд сегментүүдийг нийлэгжүүлэхдээ ачааллын хэмжээг та өөрөө сонгодог, түүнийг туннелийн MTU-ийн оронд локал интерфэйсийн MTU-аас авах нь туннель дамжуулж чадахгүй сегментүүдийг гаргадаг. Хоёрын бага руу хязгаарлана уу. Хязгаарлалт зөвхөн TCP-г хамардаг тул хэт том UDP датаграмыг таны код хуваах эсвэл хаях ёстой.
Дибаг хийх үед бичиж буй пакет бүрийн уртыг бүртгэнэ үү. Бүтэлгүйтдэг урт нь хариулт бөгөөд оролдлогын хооронд өөрчлөгдөхгүй.
Хэргүүдийг ялгах гурван хэмжилт
Хоёр эвдрэлийн аль нэгэнд нь танд дибаггер хэрэггүй. Гурван ажиглалт таныг зөв хэсэг рүү чиглүүлэхэд хангалттай бөгөөд дахин бүтээхээс бага хугацаа авдаг.
| What you see | Where to look |
|---|---|
| Reader parked, peer send queue empty, last advertised window zero | Window updates in your ACK path |
| Write fails on one length and succeeds on a smaller one | MSS clamp and tunnel MTU |
| Both directions look fine, app still sees no data | Protected socket and routing loop |
Гурав дахь мөр таарч байвал давталт өөрөө зөв бөгөөд асуудал туннель харж чадахгүй газарт байна: өөрийн VPN урсгалыг туннель рүү буцааж зөөдөг хамгаалалтгүй тээврийн сокет, энэ нь ихэвчлэн амжилттай болоод дараа нь юу ч хүргэдэггүй холболт хэлбэрээр илэрдэг.
Хоёр зам аль аль нь хамааралтай шугам хоолойг засна уу
Интерфэйс зөв баригдтал ямар ч шинж тэмдгийг мөшгих нь үнэ цэнэгүй. Чухал builder дуудлагууд нь хаяг, маршрут, MTU болон зөвшөөрөл, энэ дарааллаар:
Builder()
.addAddress(10.8.0.2, 32)
.addRoute(0.0.0.0, 0)
.setMtu(1400)
.establish()MTU-г жишээ ашигласан утга дээр үлдээхгүйгээр туннелийн бодит утгад тавина уу. Дараа нь бичих бүхэн тань тэр тоогоор хязгаарлагдана, мөн таны тавьсан MTU болон хязгаарлаж буй MSS хоорондын зөрүү нь засварын дараа бичилтийн эвдрэлийг дахин оруулах хамгийн түгээмэл арга юм. Дараа нь VPN сервер рүү урсгалыг зөөдөг сокетыг хамгаална уу. protect байхгүй бол тэдгээр пакетууд таны өөрийн туннель рүү буцаж чиглэгдэж, холболт хэзээ ч дуусдаггүй, энэ нь гатсан уншилт мэт харагдана, гэхдээ маршрутлалтын давталт юм.
Зөвшөөрлийг тойрч гарах боломжгүй. prepare null буцаахгүйгээр эхэлсэн үйлчилгээ интерфэйс авахгүй, establish нь шидэхийн оронд null буцаадаг тул давталтыг эхлүүлэхийн өмнө дескрипторыг шалгана уу. VpnService лавлагаа нь жишээ хуулахын оронд builder гэрээг баталгаажуулах газар юм.
Нэг удаад нэг чиглэлийг шалгана уу
TCP-д хүрэхийн өмнө туннелээр UDP цуурай илгээж пакетын уртыг ажиглана уу. Дараа нь гар барилтыг нээж, сегментүүд таны тооцсон MSS-ээс доогуур байгааг баталгаажуулна уу. Холболтын оронд пакетыг тоол, ингэснээр гацалт нь дүүжлэгдсэн сокетийн оронд тоолуур дахь завсарлага хэлбэрээр илэрнэ. Хэрэв бичилтүүдийн дараа уншилт зогсвол цонх сэжигтэй; хэрэв бичилт шууд бүтэлгүйтвэл урт нь.
Дараа нь төхөөрөмжийг дахин ачаалж нэг удаа давтана уу, учир нь зөвхөн эхний сүлжээний өөрчлөлт хүртэл ажилладаг VpnService нь урсгалын хяналт биш, маршрутлалтын асуудал юм.