Android VPN: deskriptor VpnService proti root tun napravi
Aplikacije Android ne morejo same ustvariti tun0: kaj vrne establish(), kje se ustavi Binder in kje se začne JNI, in kdaj zmaga naprava, ki jo ustvari root.
Dve poti lahko postavita vmesnik IP pred aplikacijo Android in obe se končata pri isti vrsti datotečnega deskriptorja z zelo različnimi lastniki. Ena gre skozi VpnService in njegov builder, druga skozi lupino root in /dev/net/tun. Vsako branje s tega deskriptorja je odhodni paket, vsak zapis pa vhodni. Poti ločuje to, kdo drži politiko, kaj preživi nadgradnjo OS in koliko usmerjevalne tabele smeš spreminjati.
Izberi pot platforme, razen če znaš poimenovati konkretno stvar, ki jo zavrača. Ta zavrnitev je običajno TAP, zajem zunaj tvojega nabora aplikacij ali usmerjevalno pravilo, ki ga ogrodje nikoli ne razkrije.
Na poti platforme deklariraš namero namesto ukazov. Navedeš vsaj en naslov, želene poti, strežnike DNS in izbirni seznam aplikacij, nato sistemska storitev Androida izvede privilegirano nastavitev pod svojo identiteto. Imena vmesnika se nikoli ne naučiš vnaprej in nikoli ne izdaš ioctl, ki ga ustvari, in prav to je bistvo.
Dva načina, kako dobiti vmesnik IP
Pot root je starejši recept. Odpreš /dev/net/tun, pokličeš TUNSETIFF z IFF_TUN, dvigneš vmesnik z ip link in ročno dodaš naslove ter poti. Vsak korak moraš narediti pravilno sam, tudi tiste, ki bi jih ogrodje opravilo tiho. Ena manjkajoča pot uporabniku da enako poročilo kot mrtev strežnik.
Odpravljanje napak se razlikuje enako kot nastavitev. Na poti root vmesnik bodisi obstaja bodisi je tvoj ioctl vrnil napako, ki jo lahko prebereš neposredno. Na poti platforme vmesnik obstaja šele po uspehu establish(), zato napaka pride kot izjema ali deskriptor null in ne kot vozlišče naprave, v katerem bi brskal.
Kaj establish() v resnici vrne
Builder.establish() ima tri izide in ti zahtevajo tri različne odzive. Deskriptor pomeni, da je vmesnik nastavljen in tvoj za uporabo, null pomeni, da zahteva ni šla skozi, vržena izjema pa pomeni, da jo je sistemska storitev zavrnila. Zlivanje null in uspeha v en boolean je najpogostejši način, kako aplikacija poroča o delujočem tunelu, ki nikoli ne prenese paketa. Referenca za Builder navaja zahtevo po naslovu in to je vredno prebrati, preden okriviš strežnik.
Smeri določi deskriptor, ne tvoj protokol. Branja ti dajo odhodne pakete, ki so že izbrani za VPN, zapisi pa vbrizgajo vhodne pakete nazaj v vmesnik. Tvoje lastno prenašanje šifrira, preverja in uokvirja te pakete, ker se platforma ustavi na meji paketa.
Binder je en korak, JNI je druga os
Zahteva builderja preide v sistem skozi Binder, in nekje pod tem platforma pokliče izvorni kôd, da nastavi napravo. To sta dva različna mehanizma, zložena v en klic. Binder je medprocesna komunikacija med tvojo aplikacijo in sistemsko storitvijo, medtem ko je JNI most iz Jave v izvorni kôd znotraj procesa. Branje drevesa AOSP za Android 9 naredi sklad dobeseden in velja si zapomniti, da se interna imena razredov in poti datotek med izdajami premikajo.
Kar se ne premika, je pogodba, na katero se lahko zaneseš: builder, deskriptor, ki ga vrne, in življenjski cikel storitve okoli njega. Nobena aplikacija ne bi smela klicati interne transakcije storitve ali znova ustvariti vozlišča naprave, da bi dobila vmesnik. Če je tvoja koda odvisna od imena razreda iz AOSP, se bo zlomila v izdaji, ki je nisi testiral.
TUN nosi IP, TAP nosi Ethernet
TUN je vmesnik IP. TAP je vmesnik Ethernet in ta razlika odloči, ali je premostitev sploh mogoča. Naprava TUN nima naslova MAC niti glave Ethernet za posredovanje, zato se odjemalec TUN ne more pridružiti mostu plasti 2, kako koli so zapisane poti.
VpnService ti da različico IP, ki jo potrebuje VPN na ravni aplikacije in jo lahko podpira brez surovega sklada Ethernet. Če tvoja zasnova zahteva premostitev, te pot platforme ne bo pripeljala tja, pot root pa le, če jedro in dovoljenja naprave sodelujejo.
Kjer pot root še vedno zmaga
Tri opravila potiskajo ljudi s poti platforme. Premostitev plasti 2 potrebuje TAP. Zajem prometa aplikacij zunaj tvojega obsega VPN potrebuje vidnost, ki je ogrodje ne daje. Usmerjanje po politiki, ki ga builder nikoli ne razkrije, na primer ločena tabela za eno ciljno točko, potrebuje pravila, ki jih namestiš sam.
Stroški pridejo pozneje: odklenjen bootloader ali rootirana slika, politika SELinux, ki se premika pod tabo, in naprava, ki se po OTA ne obnaša več pravilno. Rootiranega recepta tudi ni mogoče dostaviti prek običajne distribucije aplikacij, zato ga večina ekip drži kot notranjo diagnostično pot in ne kot izdelek.
Izbira med njima
Začni pri vmesniku, ki ga potrebuješ, ne pri kodi, ki jo imaš. Če je odgovor naprava TUN s potmi, omejenimi na aplikacijo, je pot platforme krajša in preživi nadgradnje. Če odgovor vključuje okvire Ethernet, zajem drugih aplikacij ali usmerjevalna pravila, ki jih builder zavrača, si na ozemlju root in bi moral to načrtovati kot obratovalni strošek.
Preverjanje, ki razreši večino sporov: najprej zgradi pot platforme, zabeleži izid establish() ločeno od stanja oddaljene seje in potrdi en paket v vsako smer. Šele nato se odloči, ali manjkajoča zmožnost upravičuje zapustitev podprte poti.