Android VPN-attribusjon: getConnectionOwnerUid mot /proc/net
Android 10 gøymer /proc/net for appar. Eit VPN får framleis pakkar, men attribusjonen flyttar til getConnectionOwnerUid, med eigne tuple- og løyvereglar.
På Android 10 og nyare får ein app som opnar /proc/net/tcp avslag på tilgang i staden for ein socket-tabell. VPN-grensesnittet bryr seg ikkje: pakkane kjem framleis, fordi tunnelen er ei rutingsavgjerd, ikkje ei filrett. Det som endra seg, er svaret på eit smalare spørsmål: «kva app eig denne tilkoplinga?» Erstatninga er ConnectivityManager.getConnectionOwnerUid, det støtta oppslaget per tilkopling, og valet mellom den gamle vanen og det nye API-et kjem an på kva av tre oppgåver du faktisk har: ta imot pakkar, attribuere ein straum eller summere bruk.
To måtar å svare på eigarspørsmålet
Før API 29 kunne ein privilegert prosess eller root lese socket-tabellane til kjernen, matche firedobbelen og finne den eigande UID-en. Det gav ei einingsovergripande oversikt i éi fil. Frå API 29 er filsystemvisinga avgrensa, og den støtta vegen er eit oppslag per tilkopling med protokollen, den lokale adressa og den eksterne adressa.
| 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 |
Samanlikninga er ikkje «gammalt mot nytt». Det er tre ulike oppgåver som før vart dekte av éi lesbar fil og no vert dekte av tre ulike grensesnitt med tre ulike kontraktar.
Den lokale adressa er endepunktet til appen
Metodesignaturen tek ein protokoll, ei lokal socket-adresse og ei ekstern socket-adresse. «Lokal» tyder sida til appen i tilkoplinga, ikkje endepunktet som tilfeldigvis er kjelda til pakken i augneblinken du undersøkjer han. Ein pakke som reiser frå den eksterne tenaren tilbake til appen, har kjelde og mål bytte om i høve til den definisjonen.
ConnectivityManager cm = getSystemService(ConnectivityManager.class);
int uid = cm.getConnectionOwnerUid(
OsConstants.IPPROTO_TCP, appLocalAddress, appRemoteAddress);Denne retningsfeilen er den vanlegaste årsaka til at eit fungerande oppslag gjev feil svar, eller ingen. Logg begge endepunkta før kallet og stadfest paret mot tilkoplinga appen faktisk opna. Adressefamilien tel òg: ei IPv4-kartlagd adresse og ei nativ IPv6-adresse er ulike tuplar, og det same er TCP- og UDP-straumar på dei same portane.
Autorisasjon og ukjende resultat er ein del av kontrakten
Oppslaget er avgrensa til autoriserte kallarar, inkludert den aktive VPN-appen for den aktuelle brukaren. Ein urelatert overvakingsapp kan ikkje gå ut frå at han kan liste opp tilkoplingane til ein annan profil, og eit uautorisert kall kan kaste eit tryggleiksunntak i staden for å returnere ein venleg feil. Handter begge utfalla eksplisitt.
Ein manglande eigar er ikkje eit pakkenamn. Straumen kan ha lukka seg mellom pakken og oppslaget, tuple-en kan vere ufullstendig, eller kallaren har rett og slett ikkje lov til å vite. Å cache det første vellukka svaret og bruke det om att seinare tilskriv ei ny tilkopling ein gammal app, noko som er verre enn å rapportere ukjent.
Når attribusjonen feilar, treng trafikken framleis ei avgjerd: blokker han der policyen krev det, tillat berre eit omfang du forstår, eller synleggjer holet. Den fallbacken høyrer til designet, ikkje til ein kommentar.
Rekneskap er eit anna spørsmål
NetworkStatsManager rapporterer bruk etter sine eigne tilgangsreglar. Det kan fortelje kor mykje ein UID overførte over ein periode; det kan ikkje fortelje eigaren av ein vilkårleg levande pakke. Nettverksfunksjonar skildrar eigenskapane til eit nettverk, ikkje ein katalog over sockets. Å blande dei tre gjev dashbord som ser konsistente ut og ikkje er det.
For det enkle tilfellet å avgjere kva appar som brukar tunnelen, uttrykkjer dei støtta listene til Android over tillatne og forbodne appar allereie policyen utan å skrape noko. Reserver attribusjon per straum til tilfella som verkeleg treng det, og budsjetter med ein vedlikehalden implementasjon som handterer retning, løyve og ukjende tilstandar samla.
Vel verktøyet etter oppgåve, og test så kantane
Viss kravet er tunnellval, bruk plattformlista. Viss det er live-attribusjon, bruk eigaroppslaget og handsam kvar ubesvarlege tuple som ukjend. Viss det er historiske totalar, bruk stats-API-et. Test deretter dei tre kantane som knekkjer naive implementasjonar: ein pakke i motsett retning, ein straum som lukkar seg før du spør, og ein kallar som ikkje er det aktive VPN-et.
Ingenting av dette krev å deaktivere SELinux, roote telefonen eller gjere kjernetabellar globalt lesbare. Avgrensinga er poenget: plattformen flytta attribusjonen bak ein kontrakt slik at svaret er tilgjengeleg for komponenten som legitimt treng det, og for ingen andre.