Android VpnService: megakadó TUN-olvasás kontra ENOBUFS-írási hibák
A soha vissza nem térő olvasás és az ENOBUFS-szal meghiúsuló írás ellentétes okokra vezethető vissza. Mérje meg a hirdetett ablakot és a csomaghosszt a javítás kiválasztásához.
Két tünet jelenik meg ugyanabban a VpnService-ciklusban, és mindkettőt ugyanarra fogják: egy olvasó, amely soha nem tér vissza, és egy írás, amely ENOBUFS-szal hiúsul meg. Ezek nem egyetlen hiba változatai. A megakadt olvasás a társféllal való folyamatszabályozási nézeteltérés; a sikertelen írás egy csomag, amelyet az interfész nem fogad el. Ha egy problémaként kezeli őket, egy napot tölt olyan pufferek hangolásával, amelyek soha nem voltak érintettek. Az alábbi felosztás az, ahogy eldöntöm, a ciklus melyik felét mérjem először.
Egy ciklus, két független hiba pont
A szolgáltatás IP-csomagot olvas a TUN fájlleíróból, megvizsgálja, majd választ ír ugyanabba a leíróba. Minden, ami ezen az úton elromlik, e két hívás valamelyikénél jelentkezik, ezért mindkettőt törött alagútként jelentik. A hívások szerződése eltér. Az olvasás arra vár, hogy a kernel átadjon egy csomagot, az írás pedig olyan csomagot ad át a kernelnek, amelyet az visszautasíthat.
Az olvasások a könnyebb fél, amelyen gondolkodni lehet. Az az olvasás, amely semmit nem ad vissza, vagy soha meg nem érkező forgalomra vár, vagy azért vár, mert a társfél abbahagyta a küldést.
A megakadt olvasás folyamatszabályozási nézeteltérés
A TUN-eszköz olvasása addig blokkol, amíg csomag nem érhető el. Ez tervezett viselkedés, és ezért tűnik normálisnak egy read belsejében parkoló szál egy tétlen kapcsolaton. Akkor válik akadássá, amikor a saját TCP-verem továbbra is fogad adatot a helyi alkalmazástól, de soha nem hirdet elég ablakot ahhoz, hogy a távoli társfél többet küldhessen. A társfél megtölti a hirdetett ablakot, vár egy ACK-ra és egy ablakfrissítésre, majd megáll. Ekkor az olvasónak nincs mit visszaadnia, és az alkalmazás egy nyitott és csendes kapcsolatot lát.
A gyakori okok egy olyan verem, amely a hirdetett ablak követése nélkül ír a socketbe, és egy másik, amely elfelejti elküldeni az ablakfrissítést a puffere kiürítése után. Kívülről azonosnak látszanak: bájtok mennek ki, semmi nem jön vissza, hiba nem keletkezik. Az olvasószál blokkolása elemzésen, DNS-feloldáson vagy lemez-I/O-n ugyanolyan alakú tünetet okoz független okból, ezért erősítse meg, hogy a szál valóban a read belsejében van, mielőtt a folyamatszabályozást hibáztatná.
Ellenőrizze a társfél küldési sorát és az utoljára látott ablakot. Ha a társfél azért tart vissza adatot, mert az ablak nulla, a javítás az ACK-útvonalban van, nem a TUN-olvasásban.
Az ENOBUFS méretprobléma, nem pufferszűke
A TUN-interfészen ENOBUFS-t visszaadó írás általában a csomaghosszt utasítja el. Az interfésznek van MTU-ja, az annál nagyobb csomag nem sorolható be, és ugyanazon csomag újrapróbálása minden alkalommal ugyanúgy meghiúsul. Ez a determinizmus a nyom. A valódi pufferszűke enyhül, ahogy a nyomás csökken, míg a méret elutasítása nem törődik azzal, mennyit vár.
A TCP-nek pont erre van mechanizmusa, és ez az a lépés, amelyet az emberek kihagynak: az MSS-korlát. Amikor felhasználói térben állít elő szegmenseket, Ön választja a hasznos teher méretét, és ha azt a helyi interfész MTU-jából veszi az alagút MTU-ja helyett, olyan szegmenseket bocsát ki, amelyeket az alagút nem tud szállítani. Korlátozza a kettő közül a kisebbre. A korlát csak a TCP-re vonatkozik, ezért a túl nagy UDP-datagramot a kódjának kell darabolnia vagy eldobnia.
Naplózza minden írt csomag hosszát a hibakeresés során. A meghiúsuló hossz a válasz, és nem fog változni a próbálkozások között.
Három mérés, amely szétválasztja az eseteket
Egyik hiba esetén sem kell hibakereső. Három megfigyelés elég ahhoz, hogy a megfelelő szakaszhoz irányítsa magát, és kevesebb időt vesz igénybe, mint egy újraépítés.
| 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 |
Ha a harmadik sor illeszkedik, maga a ciklus rendben van, és a probléma ott van, ahol az alagút nem látja: egy védelem nélküli átviteli socket, amely a saját VPN-forgalmát visszaviszi az alagútba, ami általában úgy jelenik meg, mint egy kapcsolat, amely sikeres lesz, majd nem szállít semmit.
Javítsa meg a vízvezetéket, amelytől mindkét útvonal függ
Egyetlen tünet sem érdemel üldözést, amíg az interfész helyesen fel nem épül. A fontos builder-hívások a cím, az útvonal, az MTU és a hozzájárulás, ebben a sorrendben:
Builder()
.addAddress(10.8.0.2, 32)
.addRoute(0.0.0.0, 0)
.setMtu(1400)
.establish()Állítsa az MTU-t az alagút valódi értékére, ahelyett hogy a példa által használt értéken hagyná. Minden, amit később ír, ehhez a számhoz kötött, és a beállított MTU valamint a korlátozott MSS közötti eltérés a leggyakoribb módja annak, hogy javítás után újra behozza az írási hibát. Ezután védje meg a socketet, amely a forgalmat magához a VPN-kiszolgálóhoz viszi. protect nélkül ezek a csomagok visszairányítódnak a saját alagútjába, és a kapcsolat soha nem jön létre, ami megakadt olvasásnak tűnik, de útvonalhurok.
A hozzájárulás nem kerülhető meg. Az a szolgáltatás, amelyet prepare null visszaadása nélkül indítanak, nem kap interfészt, és az establish null-t ad vissza dobás helyett, ezért ellenőrizze a leírót a ciklus indítása előtt. A VpnService-referencia az a hely, ahol a builder szerződését megerősítheti ahelyett, hogy egy példát másolna.
Egyszerre egy irányt ellenőrizzen
Küldjön UDP-visszhangot az alagúton, és figyelje a csomaghosszakat, mielőtt a TCP-hez nyúlna. Ezután nyisson kézfogást, és erősítse meg, hogy a szegmensek a kiszámított MSS alatt maradnak. Csomagokat számoljon, ne kapcsolatokat, hogy az akadás a számláló hézagaként jelenjen meg, ne függő socketként. Ha az olvasások egy írási sorozat után leállnak, az ablak a gyanús; ha az írások azonnal meghiúsulnak, a hossz az.
Ezután indítsa újra az eszközt, és ismételje meg egyszer, mert a VpnService, amely csak az első hálózatváltásig működik, útvonalprobléma, nem folyamatszabályozási.