Android VPN-attribution: getConnectionOwnerUid kontra /proc/net
Android 10 skjuler /proc/net for apps. En VPN får stadig pakker, men attribueringen flytter til getConnectionOwnerUid med sine egne tuple- og tilladelsesregler.
På Android 10 og nyere får en app, der åbner /proc/net/tcp, afvist adgang i stedet for en socket-tabel. VPN-interfacet er ligeglad: pakkerne ankommer stadig, fordi tunnelen er en routingbeslutning, ikke en filtilladelse. Det, der ændrede sig, er svaret på et snævrere spørgsmål: »hvilken app ejer denne forbindelse?« Erstatningen er ConnectivityManager.getConnectionOwnerUid, den understøttede forespørgsel pr. forbindelse, og valget mellem den gamle vane og det nye API afhænger af, hvilken af tre opgaver du faktisk har: at modtage pakker, at attribuere en strøm eller at summere forbrug.
To måder at besvare ejerspørgsmålet
Før API 29 kunne en privilegeret proces eller root læse kernens socket-tabeller, matche firdobbeltnøglen og finde den ejende UID. Det gav et inventar for hele enheden i én fil. Fra API 29 er filsystemets visning begrænset, og den understøttede vej er en forespørgsel pr. forbindelse med protokollen, den lokale adresse og den fjerne adresse.
| 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 |
Sammenligningen er ikke »gammelt mod nyt«. Det er tre forskellige opgaver, som før blev løst af én læsbar fil og nu løses af tre forskellige grænseflader med tre forskellige kontrakter.
Den lokale adresse er appens endepunkt
Metodens signatur tager en protokol, en lokal socket-adresse og en fjern socket-adresse. »Lokal« betyder appens side af forbindelsen, ikke det endepunkt, der tilfældigvis er pakkens kilde i det øjeblik, du undersøger den. En pakke, der rejser fra den fjerne server tilbage til appen, har sin kilde og destination ombyttet i forhold til den definition.
ConnectivityManager cm = getSystemService(ConnectivityManager.class);
int uid = cm.getConnectionOwnerUid(
OsConstants.IPPROTO_TCP, appLocalAddress, appRemoteAddress);Denne retningsfejl er den mest almindelige årsag til, at en fungerende forespørgsel giver det forkerte svar eller intet. Log begge endepunkter før kaldet, og bekræft parret mod den forbindelse, appen faktisk åbnede. Adressefamilien betyder også noget: en IPv4-mappet adresse og en native IPv6-adresse er forskellige tuples, og det samme er TCP- og UDP-strømme på de samme porte.
Autorisation og ukendte resultater er en del af kontrakten
Forespørgslen er begrænset til autoriserede kaldere, herunder den aktive VPN-app for den relevante bruger. En urelateret overvågningsapp kan ikke antage, at den kan opregne en anden profils forbindelser, og et uautoriseret kald kan kaste en sikkerhedsundtagelse i stedet for at returnere en venlig fejl. Håndtér begge udfald eksplicit.
En manglende ejer er ikke et pakkenavn. Strømmen kan være lukket mellem pakken og forespørgslen, tuplet kan være ufuldstændigt, eller den, der kalder, må måske simpelthen ikke vide det. At cache det første vellykkede svar og genbruge det senere tilskriver en ny forbindelse til en gammel app, hvilket er værre end at rapportere ukendt.
Når attribueringen fejler, har trafikken stadig brug for en beslutning: bloker den, hvor politikken kræver det, tillad kun et omfang, du forstår, eller vis hullet. Den fallback hører i designet, ikke i en kommentar.
Regnskab er et andet spørgsmål
NetworkStatsManager rapporterer forbrug under sine egne adgangsregler. Den kan fortælle, hvor meget en UID overførte over en periode; den kan ikke fortælle ejeren af en vilkårlig levende pakke. Netværksfunktioner beskriver et netværks egenskaber, ikke en mappe over sockets. At blande de tre giver dashboards, der ser konsistente ud og ikke er det.
Til det enkle tilfælde at afgøre, hvilke apps der bruger tunnelen, udtrykker Androids understøttede lister over tilladte og forbudte apps allerede politikken uden at scrape noget. Reserver attribuering pr. strøm til de tilfælde, der virkelig har brug for den, og budgetter med en vedligeholdt implementering, der håndterer retning, tilladelser og ukendte tilstande samlet.
Vælg værktøjet efter opgaven, og test så kanterne
Hvis kravet er tunnelvalg, brug platformens liste. Hvis det er live-attribuering, brug ejerforespørgslen og behandl hvert ubesvarligt tuple som ukendt. Hvis det er historiske totaler, brug stats-API'et. Test derefter de tre kanter, der knækker naive implementeringer: en pakke i modsat retning, en strøm, der lukkes før du forespørger, og en kalder, der ikke er den aktive VPN.
Intet af dette kræver, at du deaktiverer SELinux, rooter telefonen eller gør kernetabeller globale læsbare. Begrænsningen er pointen: platformen flyttede attribueringen bag en kontrakt, så svaret er tilgængeligt for den komponent, der legitimt har brug for det, og for ingen andre.