Երկու ուղի կարող են IP ինտերֆեյս դնել Android հավելվածի առաջ, և երկուսն էլ ավարտվում են նույն տեսակի ֆայլի նկարագրիչով՝ շատ տարբեր սեփականատերերով։ Մեկը անցնում է VpnService-ով և նրա builder-ով, մյուսը՝ root shell-ով և /dev/net/tun-ով։ Այդ նկարագրիչի վրա յուրաքանչյուր ընթերցում ելքային փաթեթ է, իսկ յուրաքանչյուր գրառում՝ մուտքային։ Ուղիները բաժանում է այն, թե ով է պահում քաղաքականությունը, ով է վերապրում ՕՀ-ի թարմացումը, և որքանը երթուղային աղյուսակից կարող ես դիպչել։

Ընտրիր հարթակի ուղին, եթե չես կարող անվանել այն կոնկրետ բանը, որից այն հրաժարվում է։ Այդ մերժումը սովորաբար TAP-ն է, քո իսկ հավելվածների հավաքածուից դուրս որսալը, կամ երթուղային կանոն, որը շրջանակը երբեք չի բացահայտում։

Հարթակի ուղու վրա դու հրահանգների փոխարեն հայտարարում ես մտադրություն։ Տրամադրում ես առնվազն մեկ հասցե, ցանկալի երթուղիները, DNS սերվերներ և ընտրովի հավելվածների ցանկ, ապա Android-ի համակարգային ծառայությունը կատարում է արտոնյալ կարգավորումը իր իսկ ինքնությամբ։ Դու երբեք նախապես չես իմանում ինտերֆեյսի անունը և երբեք չես արձակում այն ioctl-ը, որը ստեղծում է այն, և հենց դա է իմաստը։

IP ինտերֆեյս ստանալու երկու եղանակ

root ուղին ավելի հին բաղադրատոմսն է։ Բացում ես /dev/net/tun-ը, կանչում TUNSETIFF-ը IFF_TUN-ով, բարձրացնում ինտերֆեյսը 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()-ի արդյունքը առանձին հեռավոր սեսիայի վիճակից, և հաստատիր մեկ փաթեթ յուրաքանչյուր ուղղությամբ։ Միայն դրանից հետո որոշիր՝ արդյոք բացակայող հնարավորությունը արդարացնում է աջակցվող ուղուց հեռանալը։

Առնչվող հոդվածներ