Atribúcia VPN v systéme Android: getConnectionOwnerUid verzus /proc/net
Android 10 skrýva /proc/net pred aplikáciami. VPN stále dostáva pakety, ale atribúcia sa presúva na getConnectionOwnerUid s vlastnými pravidlami pre tuple a povolenia.
Vo verzii Android 10 a novších dostane aplikácia, ktorá otvorí /proc/net/tcp, odmietnutie prístupu namiesto tabuľky socketov. Rozhranie VPN to nezaujíma: pakety stále prichádzajú, pretože tunel je rozhodnutie o smerovaní, nie povolenie súboru. Zmenila sa odpoveď na užšiu otázku: „ktorá aplikácia vlastní toto pripojenie?“ Náhradou je ConnectivityManager.getConnectionOwnerUid, podporovaný dotaz na pripojenie, a voľba medzi starým zvykom a novým API závisí od toho, ktorú z troch úloh skutočne máte: prijímanie paketov, atribúciu toku alebo sčítavanie spotreby.
Dva spôsoby, ako odpovedať na otázku vlastníka
Pred API 29 mohol privilegovaný alebo root proces čítať tabuľky socketov jadra, spárovať štvorcu a zistiť vlastniaci UID. To dávalo inventár celého zariadenia v jednom súbore. Od API 29 je pohľad na súborový systém obmedzený a podporovanou cestou je dotaz na pripojenie s protokolom, lokálnou adresou a vzdialenou adresou.
| Question | Legacy socket tables | getConnectionOwnerUid |
|---|---|---|
| Who owns this flow? | Scan and match the tuple | Ask once per tuple |
| Device-wide inventory? | Yes, when readable | No, one flow at a time |
| Historical usage? | No | No; that is NetworkStatsManager |
| Works without root? | No on modern releases | Yes, for authorized callers |
Porovnanie nie je „staré proti novému“. Sú to tri rôzne úlohy, ktoré predtým uspokojoval jeden čitateľný súbor a teraz ich uspokojujú tri rôzne rozhrania s tromi rôznymi zmluvami.
Lokálna adresa je koniec aplikácie
Signatúra metódy prijíma protokol, lokálnu adresu socketu a vzdialenú adresu socketu. „Lokálna“ znamená stranu aplikácie v pripojení, nie ten koniec, ktorý sa v čase kontroly náhodou stal zdrojom paketu. Paket putujúci zo vzdialeného servera späť k aplikácii má zdroj a cieľ podľa tejto definície obrátené.
ConnectivityManager cm = getSystemService(ConnectivityManager.class);
int uid = cm.getConnectionOwnerUid(
OsConstants.IPPROTO_TCP, appLocalAddress, appRemoteAddress);Táto chyba smeru je najčastejším dôvodom, prečo funkčný dotaz vráti nesprávnu odpoveď alebo žiadnu. Zaznamenajte oba konce pred volaním a overte pár voči pripojeniu, ktoré aplikácia skutočne otvorila. Na rodine adries tiež záleží: adresa mapovaná cez IPv4 a natívna adresa IPv6 sú rôzne štvorce, rovnako ako toky TCP a UDP na tých istých portoch.
Autorizácia a neznáme výsledky sú súčasťou zmluvy
Dotaz je obmedzený na oprávnených volajúcich, vrátane aktívnej aplikácie VPN pre príslušného používateľa. Nesúvisiaca monitorovacia aplikácia nemôže predpokladať, že vypíše pripojenia iného profilu, a neoprávnené volanie môže vyhodiť bezpečnostnú výnimku namiesto priateľskej chyby. Oba výsledky riešte explicitne.
Chýbajúci vlastník nie je názov balíka. Tok sa mohol uzavrieť medzi paketom a dotazom, štvorica môže byť neúplná alebo volajúcemu jednoducho nie je dovolené to vedieť. Uloženie prvej úspešnej odpovede a jej neskoršie použitie priradí nové pripojenie starej aplikácii, čo je horšie než hlásiť neznáme.
Keď atribúcia zlyhá, prevádzka stále potrebuje rozhodnutie: zablokovať ju tam, kde to politika vyžaduje, povoliť len rozsah, ktorému rozumiete, alebo ukázať medzeru. Tento záložný postup patrí do návrhu, nie do komentára.
Účtovníctvo je iná otázka
NetworkStatsManager hlási spotrebu podľa vlastných pravidiel prístupu. Môže povedať, koľko UID preniesol za obdobie; nemôže povedať vlastníka ľubovoľného živého paketu. Schopnosti siete opisujú vlastnosti siete, nie adresár socketov. Miešanie troch vecí dáva dashboardy, ktoré vyzerajú konzistentne a nie sú.
Pre jednoduchý prípad rozhodnutia, ktoré aplikácie používajú tunel, už podporované zoznamy povolených a zakázaných aplikácií v Androide vyjadrujú politiku bez akéhokoľvek scrapovania. Atribúciu po toku si nechajte pre prípady, ktoré ju naozaj potrebujú, a počítajte s udržiavanou implementáciou, ktorá rieši smer, povolenia aj neznáme stavy spoločne.
Vyberte nástroj podľa úlohy, potom testujte okraje
Ak je požiadavkou voľba tunela, použite zoznam platformy. Ak ide o živú atribúciu, použite dotaz na vlastníka a každú štvorcu bez odpovede berte ako neznámu. Ak ide o historické súčty, použite stats API. Potom otestujte tri okraje, ktoré lámu naivné implementácie: paket v opačnom smere, tok, ktorý sa uzavrie pred dotazom, a volajúceho, ktorý nie je aktívna VPN.
Nič z toho nevyžaduje vypnutie SELinuxu, root telefónu ani globálne čitateľné tabuľky jadra. Obmedzenie je pointa: platforma presunula atribúciu za zmluvu, aby odpoveď bola dostupná komponentu, ktorý ju legitímne potrebuje, a nikomu inému.