Android 10 ir naujesnėse versijose programa, kuri atidaro /proc/net/tcp, gauna prieigos atsisakymą vietoj socket lentelės. VPN sąsajai tai nerūpi: paketai vis dar ateina, nes tunelis yra maršrutizavimo sprendimas, o ne failo leidimas. Pasikeitė atsakymas į siauresnį klausimą: „kuri programa valdo šį ryšį?“ Pakaitalas yra ConnectivityManager.getConnectionOwnerUid, palaikoma užklausa vienam ryšiui, o pasirinkimas tarp seno įpročio ir naujos API priklauso nuo to, kurią iš trijų užduočių iš tikrųjų turite: priimti paketus, priskirti srautą ar sumuoti naudojimą.

Du būdai atsakyti į savininko klausimą

Iki API 29 privilegijuotas arba root procesas galėjo skaityti branduolio socket lenteles, suderinti ketvertą ir sužinoti savininko UID. Tai davė viso įrenginio inventorijų viename faile. Nuo API 29 failų sistemos vaizdas yra ribojamas, o palaikomas kelias yra užklausa vienam ryšiui su protokolu, vietiniu adresu ir nuotoliniu adresu.

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

Palyginimas nėra „sena prieš naują“. Tai trys skirtingos užduotys, kurias anksčiau tenkindavo vienas skaitomas failas, o dabar tenkina trys skirtingos sąsajos su trimis skirtingomis sutartimis.

Vietinis adresas yra programos galas

Metodo parašas priima protokolą, vietinį socket adresą ir nuotolinį socket adresą. „Vietinis“ reiškia programos pusę ryšyje, o ne tą galą, kuris tikrinimo metu atsitiktinai yra paketo šaltinis. Paketo, keliaujančio nuo nuotolinio serverio atgal į programą, šaltinis ir paskirties vieta pagal šį apibrėžimą yra sukeisti.

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

Ši krypties klaida yra dažniausia priežastis, kodėl veikianti užklausa grąžina neteisingą atsakymą arba jokio. Užregistruokite abu galus prieš kvietimą ir patikrinkite porą su ryšiu, kurį programa iš tikrųjų atidarė. Adresų šeima taip pat svarbi: IPv4 susietas adresas ir gimtasis IPv6 adresas yra skirtingi ketvertai, kaip ir TCP bei UDP srautai tuose pačiuose portuose.

Įgaliojimas ir nežinomi rezultatai yra sutarties dalis

Užklausa apribota įgaliotiems kvietėjams, įskaitant atitinkamo naudotojo aktyvią VPN programą. Nesusijusi stebėjimo programa negali manyti galinti išvardyti kito profilio ryšius, o neįgaliotas kvietimas gali mesti saugumo išimtį, o ne grąžinti draugišką klaidą. Tvarkykite abu rezultatus aiškiai.

Trūkstamas savininkas nėra paketo pavadinimas. Srautas galėjo būti uždarytas tarp paketo ir užklausos, ketvertas gali būti nepilnas, arba kvietėjui tiesiog neleidžiama žinoti. Pirmo sėkmingo atsakymo kaupimas ir vėlesnis pakartotinis naudojimas priskiria naują ryšį senai programai, o tai blogiau nei pranešti nežinoma.

Kai priskyrimas nepavyksta, srautui vis tiek reikia sprendimo: užblokuokite jį ten, kur to reikalauja politika, leiskite tik jūsų suprantamą apimtį arba parodykite spragą. Tas atsarginis kelias priklauso dizainui, o ne komentarui.

Apskaita yra kitas klausimas

NetworkStatsManager praneša apie naudojimą pagal savo prieigos taisykles. Jis gali pasakyti, kiek UID perdavė per laikotarpį; jis negali pasakyti savavališko gyvo paketo savininko. Tinklo galimybės apibūdina tinklo savybes, o ne socket katalogą. Sumaišius tris gaunami prietaisų skydeliai, kurie atrodo nuoseklūs ir tokie nėra.

Paprastu atveju, kai nusprendžiate, kurios programos naudoja tunelį, palaikomi Android leidžiamų ir draudžiamų programų sąrašai jau išreiškia politiką be jokio scrapinimo. Palikite priskyrimą pagal srautą tiems atvejams, kuriems jo tikrai reikia, ir numatykite biudžetą prižiūrimai įgyvendinimui, kuri kartu tvarko kryptį, leidimus ir nežinomas būsenas.

Pasirinkite įrankį pagal užduotį, tada išbandykite briaunas

Jei reikalavimas yra tunelio pasirinkimas, naudokite platformos sąrašą. Jei tai tiesioginis priskyrimas, naudokite savininko užklausą ir kiekvieną neatsakomą ketvertą laikykite nežinomu. Jei tai istorinės sumos, naudokite stats API. Tada išbandykite tris briaunas, kurios sugriauna naivias įgyvendinimus: priešingos krypties paketą, srautą, kuris užsidaro prieš užklausą, ir kvietėją, kuris nėra aktyvus VPN.

Niekas iš to nereikalauja išjungti SELinux, rootinti telefoną ar padaryti branduolio lenteles globaliai skaitomas. Apribojimas ir yra esmė: platforma perkėlė priskyrimą už sutarties, kad atsakymas būtų prieinamas komponentui, kuriam jo teisėtai reikia, ir niekam kitam.

Susiję straipsniai