Android VPN: VpnService дескриптор ба root tun төхөөрөмж
Android аппууд tun0-ыг өөрсдөө үүсгэж чадахгүй: establish() юу буцаадаг, Binder хаана зогсдог, JNI хаана эхэлдэг, root-оор үүсгэсэн төхөөрөмж хэзээ ялдаг.
Хоёр зам Android аппын өмнө IP интерфейс тавьж болох бөгөөд хоёулаа эзэмшигч нь эрс өөр ижил төрлийн файлын дескрипторт төгсдөг. Нэг нь VpnService болон түүний builder-ээр дамждаг, нөгөө нь root shell болон /dev/net/tun-аар дамждаг. Тэр дескриптор дээрх уншилт бүр гадагшлах пакет, бичилт бүр дотогшлох пакет юм. Замуудыг ялгадаг зүйл бол бодлого хэний гарт байгаа, хэн OS-ийн шинэчлэлтийг даван туулах, маршрутын хүснэгтийн хэр ихэд хүрч чадах вэ гэдэг.
Платформын замыг сонго, хэрэв түүний хийхээс татгалздаг тодорхой зүйлийг нэрлэж чадахгүй бол л өөр зам руу яв. Энэ татгалзал ихэвчлэн TAP, өөрийн аппын багцаас гадна барих, эсвэл фреймворк хэзээ ч илрүүлдэггүй маршрутын дүрэм юм.
Платформын зам дээр та командын оронд зорилгоо зарладаг. Хамгийн багадаа нэг хаяг, хүссэн маршрут, DNS сервер, сонголтоор аппын жагсаалт өгдөг, дараа нь Android-ийн системийн үйлчилгээ өөрийн таних тэмдгээр онцгой эрхтэй тохиргоог гүйцэтгэдэг. Та интерфейсийн нэрийг урьдчилж хэзээ ч мэдэхгүй, түүнийг үүсгэдэг ioctl-ыг ч хэзээ ч гаргахгүй, энэ л гол нь.
IP интерфейс авах хоёр арга
root зам нь илүү хуучин жор юм. Та /dev/net/tun-ыг нээж, IFF_TUN-тай TUNSETIFF дуудаж, интерфейсийг ip link-ээр дээшлүүлж, хаяг, маршрутыг гараар нэмдэг. Алхам бүрийг та өөрөө зөв хийх ёстой, фреймворк чимээгүй шийдэх байсан алхмуудыг ч. Нэг маршрут дутуу бол хэрэглэгчид үхсэн сервертэй адил тайлан очно.
Дибаг хийх нь тохиргоотой адил ялгаатай. root зам дээр интерфейс байна уу, эсвэл таны ioctl шууд уншиж болох алдаа буцаасан уу. Платформын зам дээр интерфейс establish() амжилттай болсны дараа л байдаг тул бүтэлгүйтэл төхөөрөмжийн зангилааны оронд үл хамаарах зүйл эсвэл null дескриптор хэлбэрээр ирдэг.
establish() үнэхээр юу буцаадаг вэ
Builder.establish() гурван үр дүнтэй бөгөөд тэдгээр нь гурван өөр хариулт шаарддаг. Дескриптор гэдэг нь интерфейс тохируулагдсан, ашиглахад таных гэсэн үг, null нь хүсэлт дамжаагүй гэсэн үг, шидэгдсэн үл хамаарах зүйл нь системийн үйлчилгээ үүнийг татгалзсан гэсэн үг. null болон амжилтыг нэг boolean-д нэгтгэх нь пакет хэзээ ч зөөдөггүй ажиллаж буй туннелийг апп мэдээлэх хамгийн түгээмэл арга юм. Builder-ийн лавлагаа хаягийн шаардлагыг заасан бөгөөд серверийг буруутгахаас өмнө унших нь зүйтэй.
Чиглэлийг дескриптор тодорхойлдог, таны протокол биш. Уншилтууд VPN-д аль хэдийн сонгогдсон гадагшлах пакетуудыг өгдөг, бичилтүүд дотогшлох пакетуудыг интерфейс рүү буцааж шахаж оруулдаг. Тэдгээр пакетыг шифрлэх, баталгаажуулах, фрэймлэх нь таны өөрийн тээврийн ажил, учир нь платформ пакетын хил дээр зогсдог.
Binder бол нэг алхам, JNI бол өөр тэнхлэг
builder-ийн хүсэлт Binder-ээр системд нэвтэрч, түүний доор хаа нэгтээ платформ төхөөрөмжийг тохируулах натив код дууддаг. Эдгээр нь нэг дуудлага дотор овоорсон хоёр өөр механизм юм. Binder нь таны апп болон системийн үйлчилгээний хоорондын процесс хоорондын харилцаа, харин JNI нь процессын дотор Java-аас натив код руу гарах гүүр юм. Android 9 AOSP модыг уншихад стек шууд утгаараа харагдана, дотоод классын нэр, файлын зам хувилбаруудын хооронд шилждэг гэдгийг санах нь зүйтэй.
Шилждэггүй зүйл бол та найдаж болох гэрээ: builder, түүний буцаадаг дескриптор, түүний эргэн тойрон дахь үйлчилгээний амьдралын мөчлөг. Ямар ч апп интерфейс авахын тулд дотоод үйлчилгээний гүйлгээ дуудах эсвэл төхөөрөмжийн зангилаа дахин үүсгэх ёсгүй. Хэрэв таны код AOSP классын нэрээс хамааралтай бол та туршаагүй хувилбар дээр эвдэрнэ.
TUN нь IP, TAP нь Ethernet зөөдөг
TUN бол IP интерфейс. TAP бол Ethernet интерфейс бөгөөд энэ ялгаа нь гүүр барих боломжтой эсэхийг шийддэг. TUN төхөөрөмжид MAC хаяг ч, дамжуулах Ethernet толгой ч байхгүй тул TUN клиент маршрутыг хэрхэн бичсэнээс үл хамааран layer-2 гүүрт нэгдэж чадахгүй.
VpnService танд IP хувилбарыг өгдөг, энэ нь аппын түвшний VPN-д хэрэгтэй бөгөөд түүхий Ethernet стекгүйгээр дэмжиж чадах зүйл юм. Хэрэв таны дизайн гүүр шаарддаг бол платформын зам таныг тэнд хүргэхгүй, харин root зам зөвхөн цөм болон төхөөрөмжийн зөвшөөрөл хамтран ажиллавал хүргэнэ.
root зам хаана одоо ч ялдаг
Гурван ажил хүмүүсийг платформын замаас түлхдэг. layer-2 гүүр барихад TAP хэрэгтэй. Өөрийн VPN хүрээнээс гадуурх аппуудын урсгалыг барихад фреймворкийн өгдөггүй харагдах байдал хэрэгтэй. builder хэзээ ч илрүүлдэггүй бодлогын маршрутлал, жишээлбэл нэг очих газарт зориулсан тусдаа хүснэгт нь та өөрөө суулгадаг дүрмийг шаарддаг.
Зардлууд дараа ирдэг: түгжээгүй bootloader эсвэл root хийсэн имиж, таны хөл дор шилжих SELinux бодлого, OTA-ийн дараа зөв авирлахаа болих төхөөрөмж. root хийсэн жорыг ердийн апп түгээлтээр гаргах ч боломжгүй тул ихэнх баг үүнийг бүтээгдэхүүн биш дотоод оношлогооны зам болгон хадгалдаг.
Хоёрын хооронд сонголт
Гартаа байгаа кодоос биш, хэрэгтэй интерфейсээс эхэл. Хариулт нь аппаар хязгаарлагдсан маршруттай TUN төхөөрөмж бол платформын зам богино бөгөөд шинэчлэлтийг даван туулдаг. Хариулт нь Ethernet фрэйм, бусад аппыг барих, эсвэл builder-ийн татгалздаг маршрутын дүрмийг агуулж байвал та root нутагт байна, үүнийг ашиглалтын зардал болгон төсөвлөх хэрэгтэй.
Ихэнх маргааныг шийддэг шалгалт: эхлээд платформын замыг барь, establish()-ийн үр дүнг алсын сессийн төлөвөөс тусдаа тэмдэглэ, чиглэл бүрт нэг пакетыг батал. Зөвхөн дараа нь дутуу чадвар дэмжигдсэн замаас гарахыг зөвтгөж байгаа эсэхийг шийд.