Du keliai gali pastatyti IP sąsają prieš Android programėlę, ir abu baigiasi to paties tipo failo deskriptoriumi su labai skirtingais savininkais. Vienas eina per VpnService ir jo builderį, kitas per root shell ir /dev/net/tun. Kiekvienas šio deskriptoriaus skaitymas yra išeinantis paketas, o kiekvienas rašymas – įeinantis. Kelius skiria tai, kas turi politiką, kas išgyvena OS atnaujinimą ir kiek maršrutų lentelės tau leidžiama liesti.

Rinkis platformos kelią, nebent gali įvardyti konkretų dalyką, kurio ji atsisako. Tas atsisakymas paprastai yra TAP, fiksavimas už savo programėlių rinkinio ribų arba maršrutizavimo taisyklė, kurios karkasas niekada neatskleidžia.

Platformos kelyje tu deklaruoji ketinimą, o ne komandas. Pateiki bent vieną adresą, norimus maršrutus, DNS serverius ir pasirenkamą programėlių sąrašą, tada Android sistemos tarnyba atlieka privilegijuotą nustatymą savo tapatybės vardu. Sąsajos vardo niekada nesužinai iš anksto ir niekada neišduodi ioctl, kuris ją sukuria, ir tame esmė.

Du būdai gauti IP sąsają

Root kelias yra senesnis receptas. Atveri /dev/net/tun, iškvieči TUNSETIFF su IFF_TUN, pakeli sąsają su ip link ir ranka pridedi adresus bei maršrutus. Kiekvieną žingsnį turi atlikti teisingai pats, įskaitant tuos, kuriuos karkasas būtų sutvarkęs tyliai. Vieno trūkstamo maršruto naudotojas gauna tokią pačią ataskaitą kaip ir dėl mirusio serverio.

Derinimas skiriasi tiek pat, kiek ir nustatymas. Root kelyje sąsaja arba egzistuoja, arba tavo ioctl grąžino klaidą, kurią gali perskaityti tiesiogiai. Platformos kelyje sąsaja egzistuoja tik po to, kai establish() pavyksta, todėl gedimas ateina kaip išimtis arba null deskriptorius, o ne kaip įrenginio mazgas, kuriame galėtum knaisytis.

Ką establish() iš tikrųjų grąžina

Builder.establish() turi tris baigtis ir joms reikia trijų skirtingų atsakymų. Deskriptorius reiškia, kad sąsaja sukonfigūruota ir tavo naudojimui, null reiškia, kad užklausa nepraėjo, o išmesta išimtis reiškia, kad sistemos tarnyba ją atmetė. null ir sėkmės sujungimas į vieną boolean yra dažniausias būdas, kuriuo programėlė praneša apie veikiantį tunelį, kuris niekada neneša paketo. Builder nuoroda nurodo adreso reikalavimą, ir verta tai perskaityti prieš kaltinant serverį.

Kryptis nustato deskriptorius, o ne tavo protokolas. Skaitymai duoda išeinančius paketus, jau atrinktus VPN, o rašymai įpurškia įeinančius paketus atgal į sąsają. Tavo paties transportas šifruoja, autentifikuoja ir įrėmina tuos paketus, nes platforma sustoja ties paketo riba.

Binder yra vienas šuolis, JNI – kita ašis

Builder užklausa pereina į sistemą per Binder, ir kažkur žemiau platforma iškviečia natyvų kodą įrenginiui sukonfigūruoti. Tai du skirtingi mechanizmai, sukrauti viename kvietime. Binder yra tarpprocesinė komunikacija tarp tavo programėlės ir sistemos tarnybos, o JNI yra tiltas iš Java į natyvų kodą proceso viduje. Android 9 AOSP medžio skaitymas padaro steką tiesioginiu, ir verta atsiminti, kad vidiniai klasių pavadinimai bei failų keliai keičiasi tarp leidimų.

Tai, kas nesikeičia, yra sutartis, kuria gali pasikliauti: builderis, jo grąžinamas deskriptorius ir aplink jį esantis tarnybos gyvavimo ciklas. Jokia programėlė neturėtų kviesti vidinės tarnybos transakcijos ar iš naujo kurti įrenginio mazgo, kad gautų sąsają. Jei tavo kodas priklauso nuo AOSP klasės pavadinimo, jis sulūš leidime, kurio netestavai.

TUN neša IP, TAP neša Ethernet

TUN yra IP sąsaja. TAP yra Ethernet sąsaja, ir šis skirtumas lemia, ar tiltinimas apskritai įmanomas. TUN įrenginys neturi MAC adreso ir neturi perduodamos Ethernet antraštės, todėl TUN klientas negali prisijungti prie 2 lygio tilto, kad ir kaip būtų parašyti maršrutai.

VpnService duoda tau IP variantą, kurio reikia programėlės lygio VPN ir kurį jis gali palaikyti be neapdoroto Ethernet steko. Jei tavo dizainui reikia tiltinimo, platformos kelias ten neves, o root kelias – tik jei branduolys ir įrenginio leidimai bendradarbiauja.

Kur root kelias vis dar laimi

Trys darbai stumia žmones nuo platformos kelio. 2 lygio tiltinimui reikia TAP. Srauto iš programėlių už tavo VPN apimties fiksavimui reikia matomumo, kurio karkasas nesuteikia. Politika pagrįstas maršrutizavimas, kurio builderis niekada neatskleidžia, pavyzdžiui, atskira lentelė vienam tikslui, reikalauja taisyklių, kurias įdiegi pats.

Išlaidos ateina vėliau: atrakintas bootloader arba rootintas atvaizdas, po tavimi judanti SELinux politika ir įrenginys, kuris po OTA nustoja elgtis tinkamai. Rootinto recepto taip pat negalima platinti per įprastą programėlių platinimą, todėl dauguma komandų laiko jį vidiniu diagnostikos keliu, o ne produktu.

Pasirinkimas tarp jų

Pradėk nuo sąsajos, kurios tau reikia, o ne nuo kodo, kurį turi. Jei atsakymas yra TUN įrenginys su programėle apribotais maršrutais, platformos kelias trumpesnis ir išgyvena atnaujinimus. Jei atsakymas apima Ethernet kadrus, kitų programėlių fiksavimą ar maršrutizavimo taisykles, kurias builderis atmeta, tu esi root teritorijoje ir turėtum tai biudžetuoti kaip veiklos sąnaudas.

Patikra, kuri išsprendžia daugumą ginčų: pirmiausia sukurk platformos kelią, užfiksuok establish() rezultatą atskirai nuo nuotolinės sesijos būsenos ir patvirtink po vieną paketą kiekviena kryptimi. Tik tada nuspręsk, ar trūkstama galimybė pateisina palikti palaikomą kelią.

Susiję straipsniai