Android-та VPN қосылғанын код арқылы қалай тексеруге болады
Android-та VPN қосылымын қайтаратын getter жоқ. Желі мүмкіндіктерін сұраңыз, тасымал өзгерістерін бақылаңыз және қолданба келісімін, құрылғы күйін және сервер дәлелін бөлек ұстаңыз.
Android-тан VPN қосылған ба, жоқ па деп сұрай алмайсыз. VpnService қосылу күйін қайтаратын getter ұсынбайды, ал күй жолағындағы кілт белгішесін жүйе салады, қолданбаңыз оқи алатын нәрсе емес. Істей алатыныңыз — байланыс стегіне тар мағыналы сұрақ қою: бұл қолданбаның трафигі қай желіні пайдаланады және сол желі VPN тасымалын алып жүре ме. Бұл нұсқаулық жалған оң нәтижелерден сақтайтын ретпен тексерулерді өткізеді: құрылғыдағы shell командасынан қолданбада қалдыратын callback-ке дейін.
Қолданба кодына тиіспес бұрын құрылғыны shell-ден тексеріңіз
Алдымен бастапқы күйді алыңыз. adb shell dumpsys connectivity жүйе білетін барлық желіні шығарады, әр блок өз тасымалдарын тізіп көрсетеді, сондықтан VPN желісі сол тізімде VPN-мен көрінеді. Ең алдымен әдепкі желі блогын оқыңыз, содан кейін сол тасымалды алып жүретін басқа желілерді іздеңіз.
Екі шығыс әртүрлі сұраққа жауап береді. VPN желісінің болуы қолданбаңыздың оны пайдаланып жатқанымен бірдей емес, ал жұмыс профилі немесе екінші пайдаланушы бар құрылғыда процесіңіз интернетке тікелей қатынасып жатқанда екеуі де бір уақытта ақиқат болуы мүмкін. Сокеттеріңіздің не істейтінін белсенді желі жолы шешеді.
Қолданба пайдаланып жатқан желіні сұраңыз
Кодта мүмкіндік тесті төрт жол. Манифестте ACCESS_NETWORK_STATE сұраңыз, содан кейін белсенді желінің мүмкіндіктерін VPN тасымалымен салыстырыңыз:
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network active = cm.getActiveNetwork();
NetworkCapabilities caps = cm.getNetworkCapabilities(active);
boolean vpnInUse = caps != null
&& caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
Жауап әдейі тар: қолданбаның әдепкі желісі қазір VPN бе. Ол қай VPN, ол сіздікі ме, әлде туннель алыс ұшына жетті ме дегенді айтпайды. true мәнін «трафик қандай да бір туннель арқылы шығады» деп түсініп, өз есебіңізді бөлек ұстаңыз. Үш мағынаны үнсіз бірге білдіретін boolean — баптаулар экраны пайдаланушы VPN арқылы шолып жатқанда VPN өшірулі деп көрсетуінің себебі.
Керісінше, қандай да бір VPN желісінің бар-жоғын білу керек болса, cm.getAllNetworks() бойынша қайталап, әр мүмкіндік жиынын тексеріңіз. Екі жауап басқа қолданбаларды қамтитын, бірақ сіздің қолданбаңызды қамтымайтын қолданбаға тән VPN жүріп жатқан құрылғыда ажырайды және сол ажырау «анық қосулы VPN-ді қолданба көрмейді» дейтін қате хабарламалардың көпшілігінің көзі.
Polling орнына өзгерістерді бақылаңыз
Таймер бойынша polling бұл сұраққа дұрыс пішін емес, өйткені күй өзгерістері оқиға ретінде келеді. VPN тасымалына сәйкес келетін сұранысты тіркеп, сәйкес желі пайда болғанда, жоғалғанда немесе өзгергенде фреймворк өзі хабарласын:
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.build();
cm.registerNetworkCallback(request, callback);
VPN желісі ешқашан NET_CAPABILITY_NOT_VPN алып жүрмейді, сондықтан оны анық алып тастау ниетті құжаттайды. Онсыз да сұраныс сәйкес келеді, бірақ келесі оқырман мұны өзі анықтауға тура келеді.
Тіркеу бақылау қажет қамтуға тиесілі, әдетте экран немесе алдыңғы пландағы қызмет. onStop немесе onDestroy ішінде тіркеуден шығарыңыз және жойылып кеткен activity-ге callback қалдырмаңыз. Көрінетін компоненті жоқ қолданба тұрақты бақылаушы үшін нашар ие, ал ұмытылған callback-тер конфигурация өзгерісінен кейін құлайтындар.
Үш сұрақты бөлек ұстаңыз
Бұл саладағы шатасудың көпшілігі үш түрлі тексеруді бір деп қараудан туады. Олар әртүрлі API пайдаланады және біреуі ақиқат болғанда басқалары жалған болуы мүмкін.
| Question | How you answer it | What a yes means |
|---|---|---|
| Did the user grant VPN consent to my app? | VpnService.prepare() returns null | Consent exists; the tunnel may still be down |
| Is the device sending default traffic through a VPN? | TRANSPORT_VPN on the active network | Something is tunneling, not necessarily your app |
| Did this request arrive through the VPN? | Source address seen by the server | Proof for that connection, nothing wider |
Үшінші жол — адамдар клиентте жауап беруге тырысатын, бірақ онда жауап берілмейтін жол. VPN клиенттеріне жеке мекенжай пулын беріңіз және серверде бастапқы мекенжайды оқыңыз; бұл пайдаланушы сессия ортасында туннельді ауыстырса да сақталатын жалғыз дәлел.
Жалған оң нәтижелерді жоққа шығаратын тексеру реті
Әлі айналымда жүрген ескі үлгі код getNetworkInfo(ConnectivityManager.TYPE_VPN) шақырады. Бұл шақыру ескірген және бірнеше шығарылымда VPN қосулы болса да null қайтарған, сондықтан көшірілген үзінділер жұмыс істеп тұрған құрылғыда бұзылған көрінеді. Мүмкіндік тексерулері бұл тұзақтан аулақ болады және Android 5.0-ден бастап бірдей әрекет етеді. Егер әлі шақыратын код базасын ұстасаңыз, шақыруды fallback-ке орамай, оның өзін ауыстырыңыз, өйткені дұрыс емес жауапты дәл сол fallback тудырған.
Бір қысқа жол ескертуге лайық. Сыртқы қызмет хабарлаған жария мекенжайды VPN шығу мекенжайымен салыстыру жол туралы бірдеңе дәлелдейді, бірақ әр тексеруге үшінші тарап сұранысын қосады, сол қызметтің жұмыс істеп тұруына тәуелді және кэштелуі немесе блокталуы мүмкін. Оны қолмен жасалатын диагностика ретінде ұстаңыз, ешқашан қолданба ішіндегі күй тексерісі ретінде емес.
Тексерулерді осы ретпен орындаңыз және пайдаланушының хабарламасына қайшы келетін біріншісінде тоқтаңыз: shell-дегі тасымалдар тізімі, белсенді желі мүмкіндіктері, туннельді қосып-өшірген кездегі callback оқиғалары, содан кейін сервер жағындағы бастапқы мекенжай. Егер төртеуі де сәйкес келсе де қолданба қате әрекет етсе, ақау Android-тың желіні көруінде емес, өз күй машинаңызда.