На Android 10 і пазней праграма, якая адкрывае /proc/net/tcp, атрымлівае адмову ў доступе замест табліцы сокетаў. VPN-інтэрфейсу гэта не перашкаджае: пакеты прыходзяць, бо тунель — гэта рашэнне пра маршрут, а не дазвол на файл. Змяніўся адказ на больш вузкае пытанне: «якая праграма валодае гэтым злучэннем?» Замена — ConnectivityManager.getConnectionOwnerUid, падтрыманы запыт па кожным злучэнні, і выбар паміж старой звычкай і новым API залежыць ад таго, якая з трох задач у вас насамрэч ёсць: прымаць пакеты, атрыбутаваць паток або лічыць спажыванне.

Два спосабы адказаць на пытанне пра ўладальніка

Да API 29 прывілеяваны або root-працэс мог чытаць табліцы сокетаў ядра, супастаўляць чацвёрку і пазнаваць 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

Параўнанне не «старое супраць новага». Гэта тры розныя задачы, якія раней задавальняў адзін чытэльны файл, а цяпер задавальняюць тры розныя інтэрфейсы з трыма рознымі кантрактамі.

Лакальны адрас — гэта канец праграмы

Сігнатура метаду прымае пратакол, лакальны адрас сокета і аддалены адрас сокета. «Лакальны» азначае бок злучэння з боку праграмы, а не той канец, які ў момант праверкі выпадкова аказаўся крыніцай пакета. У пакета, што ідзе ад аддаленага сервера назад да праграмы, крыніца і прызначэнне перастаўлены адносна гэтага азначэння.

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

Гэтая памылка кірунку — самая частая прычына таго, што працаздольны запыт вяртае няправільны адказ або ніякі. Запішыце абодва канцы перад выклікам і зверце пару са злучэннем, якое праграма сапраўды адкрыла. Сямейства адрасоў таксама важнае: адрас, адлюстраваны праз IPv4, і ўласны адрас IPv6 — гэта розныя картэжы, як і патокі TCP і UDP на адных партах.

Аўтарызацыя і невядомыя вынікі — частка кантракта

Запыт абмежаваны аўтарызаванымі выклікальнікамі, уключаючы актыўную VPN-праграму для адпаведнага карыстальніка. Стоянняя праграма маніторынгу не можа меркаваць, што пералічыць злучэнні іншага профілю, а неаўтарызаваны выклік можа выкінуць выключэнне бяспекі замест ветлівай памылкі. Апрацоўвайце абодва вынікі яўна.

Адсутны ўладальнік — гэта не імя пакета. Паток мог зачыніцца паміж пакетам і запытам, картэж можа быць няпоўным, або выклікальніку проста не дазволена ведаць. Кэшаванне першага паспяховага адказу і яго пазнейшае выкарыстанне прыпісвае новае злучэнне старой праграме, што горш за паведамленне пра невядомасць.

Калі атрыбуцыя не ўдаецца, трафік усё роўна патрабуе рашэння: заблакаваць яго там, дзе гэта патрабуе палітыка, дазволіць толькі зразумелы вам абсяг або паказаць прагал. Гэты запасны шлях належыць дызайну, а не каментару.

Улік — гэта іншае пытанне

NetworkStatsManager паведамляе пра спажыванне паводле ўласных правілаў доступу. Ён можа сказаць, колькі UID перадаў за перыяд; ён не можа сказаць уладальніка адвольнага жывога пакета. Магчымасці сеткі апісваюць уласцівасці сеткі, а не каталог сокетаў. Змешванне трох дае панэлі, якія выглядаюць узгоднена і не ёсць такімі.

Для простага выпадку — вызначыць, якія праграмы карыстаюцца тунелем, — падтрыманыя спісы дазволеных і забароненых праграм Android ужо выяўляюць палітыку без усякага выскрэбвання. Пакіньце атрыбуцыю па патоку для выпадкаў, якім яна сапраўды патрэбна, і закладзіце бюджэт на падтрымоўваную рэалізацыю, якая разам апрацоўвае кірунак, дазволы і невядомыя станы.

Выбірайце інструмент па задачы, потым правярайце мяжы

Калі патрабаванне — выбар тунеля, выкарыстоўвайце спіс платформы. Калі гэта жывая атрыбуцыя, выкарыстоўвайце запыт уладальніка і лічыце кожны бязответны картэж невядомым. Калі гэта гістарычныя сумы, выкарыстоўвайце stats API. Затым праверце тры мяжы, якія ламаюць наіўныя рэалізацыі: пакет у адваротным кірунку, паток, што зачыняецца да запыту, і выклікальнік, які не з'яўляецца актыўным VPN.

Нішто з гэтага не патрабуе адключэння SELinux, root-права на тэлефоне або глабальна чытэльных табліц ядра. Абмежаванне — гэта і ёсць сутнасць: платформа перанесла атрыбуцыю за кантракт, каб адказ быў даступны кампаненту, якому ён законна патрэбны, і нікому іншаму.

Падобныя артыкулы