Android 10-ում և ավելի նորերում /proc/net/tcp բացող հավելվածը ստանում է մուտքի մերժում՝ socket-ների աղյուսակի փոխարեն։ VPN ինտերֆեյսին դա չի հետաքրքրում. փաթեթները շարունակում են գալ, որովհետև թունելը երթուղավորման որոշում է, ոչ թե ֆայլի թույլտվություն։ Փոխվել է ավելի նեղ հարցի պատասխանը՝ «ո՞ր հավելվածն է տիրապետում այս կապին»։ Փոխարինողը ConnectivityManager.getConnectionOwnerUid-ն է, աջակցվող հարցումը յուրաքանչյուր կապի համար, և հին սովորության ու նոր API-ի միջև ընտրությունը կախված է նրանից, թե երեք աշխատանքներից որն ունեք իրականում՝ փաթեթներ ստանալ, հոսք վերագրել կամ օգտագործումը գումարել։

Սեփականատիրոջ հարցին պատասխանելու երկու եղանակ

API 29-ից առաջ արտոնյալ կամ root պրոցեսը կարող էր կարդալ միջուկի socket-ների աղյուսակները, համադրել քառյակը և իմանալ սեփականատեր UID-ը։ Դա մեկ ֆայլում տալիս էր ամբողջ սարքի գույքագրում։ API 29-ից ֆայլային համակարգի տեսքը սահմանափակ է, և աջակցվող ուղին յուրաքանչյուր կապի հարցումն է՝ պրոտոկոլով, տեղական հասցեով և հեռավոր հասցեով։

QuestionLegacy socket tablesgetConnectionOwnerUid
Who owns this flow?Scan and match the tupleAsk once per tuple
Device-wide inventory?Yes, when readableNo, one flow at a time
Historical usage?NoNo; that is NetworkStatsManager
Works without root?No on modern releasesYes, for authorized callers

Համեմատությունը «հինն ընդդեմ նորի» չէ։ Դրանք երեք տարբեր աշխատանքներ են, որոնք նախկինում բավարարում էր մեկ ընթեռնելի ֆայլ, իսկ այժմ՝ երեք տարբեր ինտերֆեյսներ՝ երեք տարբեր պայմանագրերով։

Տեղական հասցեն հավելվածի ծայրն է

Մեթոդի ստորագրությունը վերցնում է պրոտոկոլ, տեղական socket-ի հասցե և հեռավոր socket-ի հասցե։ «Տեղականը» նշանակում է կապի հավելվածի կողմը, ոչ այն ծայրը, որը ստուգման պահին պատահաբար փաթեթի աղբյուրն է։ Հեռավոր սերվերից հավելված վերադարձող փաթեթի աղբյուրն ու նպատակակետը այդ սահմանման նկատմամբ շրջված են։

ConnectivityManager cm = getSystemService(ConnectivityManager.class);
int uid = cm.getConnectionOwnerUid(
    OsConstants.IPPROTO_TCP, appLocalAddress, appRemoteAddress);

Այս ուղղության սխալը ամենատարածված պատճառն է, որ աշխատող հարցումը սխալ պատասխան է տալիս կամ ընդհանրապես ոչ մեկը։ Գրանցեք երկու ծայրերը մինչև կանչը և հաստատեք զույգը այն կապի հետ, որը հավելվածը իրականում բացել է։ Հասցեների ընտանիքը նույնպես կարևոր է. IPv4-ով քարտեզագրված հասցեն և սեփական IPv6 հասցեն տարբեր քառյակներ են, ինչպես նաև նույն պորտերի TCP և UDP հոսքերը։

Լիազորումը և անհայտ արդյունքները պայմանագրի մասն են

Հարցումը սահմանափակված է լիազորված կանչողներով, ներառյալ համապատասխան օգտատիրոջ ակտիվ VPN հավելվածը։ Անկապ մոնիթորինգի հավելվածը չի կարող ենթադրել, որ կարող է թվարկել այլ պրոֆիլի կապերը, և չլիազորված կանչը կարող է նետել անվտանգության բացառություն՝ ընկերական սխալի փոխարեն։ Կարգավորեք երկու արդյունքներն էլ բացահայտ։

Բացակա սեփականատերը փաթեթի անուն չէ։ Հոսքը կարող էր փակվել փաթեթի և հարցման միջև, քառյակը կարող է թերի լինել, կամ կանչողին պարզապես չի թույլատրվում իմանալ։ Առաջին հաջող պատասխանը պահելը և հետագայում վերաօգտագործելը նոր կապը վերագրում է հին հավելվածին, ինչը ավելի վատ է, քան անհայտ հայտնելը։

Երբ վերագրումը ձախողվում է, երթևեկությունը դեռ որոշում է պահանջում. արգելափակել այնտեղ, որտեղ քաղաքականությունը պահանջում է, թույլատրել միայն ձեր հասկացած շրջանակը, կամ ցույց տալ բացը։ Այդ պահուստը պատկանում է դիզայնին, ոչ մեկնաբանությանը։

Հաշվառումը այլ հարց է

NetworkStatsManager-ը հաղորդում է օգտագործման մասին իր սեփական մուտքի կանոններով։ Այն կարող է ասել, թե որքան է UID-ը փոխանցել ժամանակահատվածում. այն չի կարող ասել կամայական կենդանի փաթեթի սեփականատիրոջը։ Ցանցի հնարավորությունները նկարագրում են ցանցի հատկություններ, ոչ թե socket-ների տեղեկատու։ Երեքը խառնելը ստեղծում է վահանակներ, որոնք հետևողական են թվում և այդպիսին չեն։

Պարզ դեպքում՝ որոշելու, թե որ հավելվածներն են օգտագործում թունելը, Android-ի աջակցվող թույլատրված և արգելված հավելվածների ցանկերն արդեն արտահայտում են քաղաքականությունը՝ առանց որևէ scraping-ի։ Պահեք հոսքի վերագրումը այն դեպքերի համար, որոնք իսկապես դրա կարիքն ունեն, և բյուջե նախատեսեք պահպանվող իրականացման համար, որը միասին կարգավորում է ուղղությունը, թույլտվությունները և անհայտ վիճակները։

Ընտրեք գործիքն ըստ աշխատանքի, ապա փորձարկեք եզրերը

Եթե պահանջը թունելի ընտրությունն է, օգտագործեք հարթակի ցանկը։ Եթե դա կենդանի վերագրում է, օգտագործեք սեփականատիրոջ հարցումը և յուրաքանչյուր անպատասխան քառյակ համարեք անհայտ։ Եթե դրանք պատմական գումարներ են, օգտագործեք stats API-ը։ Ապա փորձարկեք երեք եզրերը, որոնք կոտրում են միամիտ իրականացումները՝ հակառակ ուղղության փաթեթ, հարցումից առաջ փակվող հոսք և կանչող, որը ակտիվ VPN-ը չէ։

Այս ոչ մեկը չի պահանջում անջատել SELinux-ը, root անել հեռախոսը կամ միջուկի աղյուսակները դարձնել համաշխարհային ընթեռնելի։ Սահմանափակումը հենց իմաստն է. հարթակը վերագրումը տեղափոխեց պայմանագրի հետևում, որպեսզի պատասխանը հասանելի լինի այն բաղադրիչին, որն օրինականորեն դրա կարիքն ունի, և ոչ ոքի այլ։

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