Y prawf y mae'r rhan fwyaf o apiau Android yn ei ddefnyddio i ganfod VPN yw enw rhyngwyneb, ac nid oedd erioed yn brawf VPN. Mae'n adrodd bod rhyw ryngwyneb yn bodoli gyda llinyn yr oedd y datblygwr yn ei ddisgwyl, sydd ar un ddyfais yn golygu OpenVPN ac ar un arall yn golygu rhywbeth hollol ddi-gysylltiad. Mae ping yr un fath o dystiolaeth: mae'n profi bod un cyrchfan wedi ateb, nid bod twnnel wedi cario'r pecyn. Yr hyn y mae'r platfform yn ei ddatgelu mewn gwirionedd yw set o rwydweithiau a'r trafnidiaethau y mae pob un yn eu datgan, ac mae hynny'n gwestiwn gwahanol ag ateb gwahanol.

Myth: os yw tun0 yn bodoli, mae VPN i fyny

Mae apiau VPN Android yn weithrediadau VpnService sy'n rhoi disgrifydd ffeil tun i'r system. Daw enw'r rhyngwyneb oddi wrth pwy bynnag a'i creodd: mae OpenVPN fel arfer yn cynhyrchu tun0, mae PPTP a L2TP yn cynhyrchu ppp0, mae WireGuard yn enwi ei ryngwyneb ar ôl y twnnel, ac efallai na fydd twnnel IPsec yn cyflwyno enw confensiynol o gwbl. Felly mae darllen /proc/net/dev neu restru gwrthrychau NetworkInterface yn chwilio am gonfensiwn, nid am ffaith.

Mae'r ddau gyfeiriad gwall yn fyw. Gall dyfais fod â tun0 ar gyfer twnnel lleol nad oes ganddo ddim i'w wneud â VPN y defnyddiwr, a gall twnnel WireGuard hollol iach fod yn anweledig i brawf nad yw'n adnabod ond y llinyn tun0. Mae canlyniadau positif ffug a negatif ffug yn yr un ffwythiant yn ei wneud yn ddiwerth fel diagnostig, oherwydd ni ellir ymddiried mewn tocyn cymorth sy'n dweud „ni chanfuwyd VPN” i'r naill gyfeiriad na'r llall.

Mae mynediad hefyd wedi culhau. Mae rhyddhau Android mwy diweddar yn cyfyngu ar yr hyn y gall ap cyffredin ei ddarllen o /proc, felly gall prawf sy'n seiliedig ar enw a weithiodd ar Android 8 ddychwelyd rhestr wag ar ddyfais hwyrach heb unrhyw newid cod. Pan fydd y prawf yn methu'n dawel ar agor, mae'r ap yn casglu nad oes VPN ar galedwedd lle mae'r twnnel yn iawn.

Myth: mae ping llwyddiannus yn golygu bod y twnnel yn cario traffig

Mae ping i westeiwr mewnol yn llwyddo pryd bynnag y bo llwybr i'r gwesteiwr hwnnw. Gyda thwnelu hollt, gall y gwesteiwr fod yn gyrraeddadwy dros Wi-Fi tra bod y twnnel i fyny ac yn gwneud rhywbeth hollol wahanol. Gyda VPN fesul ap, gall yr ap sy'n gwneud y ping gael ei eithrio o'r twnnel, felly mae'r adlais ICMP yn gadael y tu allan iddo ac yn dod yn ôl, sy'n profi'r gwrthwyneb i'r hyn y mae'r prawf yn ei dybio.

Mae ICMP a TCP hefyd yn cael eu hidlo ar wahân. Bydd twnnel sy'n caniatáu ceisiadau adlais ond yn gollwng y porth TCP y mae gwasanaeth ei angen yn pasio'r prawf ping ac yn methu yn yr ap, ac mae hynny'n rheol wal dân ar yr ochr bellach yn hytrach na nodwedd o'r ddyfais. Yr unig ddarlleniad gonest o bing llwyddiannus yw bod y gyrchfan hon wedi ateb y protocol hwn ar yr eiliad hon.

Yr hyn y mae'r platfform yn ei adrodd mewn gwirionedd

O API 21 ymlaen mae ConnectivityManager.getAllNetworks() yn dychwelyd pob rhwydwaith y mae'r system yn ei adnabod, ac mae getNetworkCapabilities(network) yn adrodd yr hyn y mae'r rhwydwaith hwnnw'n ei ddatgan. Mae rhwydwaith VPN yn cario TRANSPORT_VPN. Mae dolen dros bob rhwydwaith yn ateb un cwestiwn: a oes unrhyw VPN i fyny ar y ddyfais hon ar hyn o bryd?

Mae ail gwestiwn, culach, angen galwad wahanol. Mae getActiveNetwork() yn dychwelyd y rhwydwaith y byddai traffig yr ap yn ei ddefnyddio nawr, ac mae gwirio'r un gallu arno yn ateb: a fyddai fy nhraffig yn mynd trwy VPN? Gall y ddau anghytuno, ac mae'r anghytundeb yn addysgiadol. Mae VPN sydd i fyny ond nad yw'n weithredol yn cyfeirio at lwybr fesul ap neu at ffurfweddiad twnnel hollt, nid at dwnnel ar goll.

Network active = cm.getActiveNetwork();
NetworkCapabilities caps = cm.getNetworkCapabilities(active);
boolean viaVpn = caps != null
    && caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);

Diogelwch y ddwy alwad. Gall galluoedd fod yn null ar gyfer rhwydwaith a ddiflannodd rhwng rhestru a holi, a gall y rhwydwaith gweithredol fod yn null yn ystod trosglwyddiad. Mae NET_CAPABILITY_NOT_VPN yn ddefnyddiol i'r cyfeiriad arall, i gadarnhau bod rhwydwaith yn bendant nid yn dwnnel yn hytrach na dim ond yn colli'r faner drafnidiaeth VPN.

Yr un myth oedd NetworkInfo gydag API

Mae ConnectivityManager.TYPE_VPN gyda NetworkInfo yn ail genhedlaeth y prawf hwn, ac mae wedi darfod am reswm. Ar ryddhau modern gall y gwrthrych a ddychwelir ar gyfer VPN fod yn null tra bod y twnnel wedi'i gysylltu, felly mae cod sy'n trin null fel „dim VPN” yn adrodd negatif ffug yn dawel ar y dyfeisiau lle mae'r ateb yn bwysicaf.

Nid yw'r darllediad sy'n ei gyd-fynd fel arfer yn well chwaith. Mae gan CONNECTIVITY_CHANGE hanes dogfennedig o fethu trosglwyddiadau VPN, gan gynnwys adeiladau lle'r oedd yn tanio dim ond pan oedd VPN yn cysylltu neu'n datgysylltu yn hytrach nag ar bob newid rhwydwaith. Mae gwrandäwr a adeiledir arno yn cynhyrchu newidyn cyflwr sy'n crwydro oddi wrth olwg y platfform hyd at yr ailgysylltiad llawn nesaf.

Ymatebwch i alwadau yn ôl yn lle arolygu

Cofrestrwch NetworkRequest sy'n gofyn am TRANSPORT_VPN ac yn tynnu NET_CAPABILITY_NOT_VPN, yna galwch registerNetworkCallback â'r cais hwnnw. Yna mae onAvailable ac onLost yn dweud wrthych pan fydd y datganiad yn newid, a dyna'r digwyddiad y mae gwir angen i chi ei gael. Dad-gofrestrwch yr alwad yn ôl pan fydd y gydran yn stopio, neu bydd yr ap yn cadw cyfeiriad at sgrin farw ac mae'r alwad yn ôl yn parhau i danio.

NetworkRequest req = new NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
    .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
    .build();
cm.registerNetworkCallback(req, callback);

Mae hyn angen ACCESS_NETWORK_STATE, sy'n ganiatâd arferol: dim root, dim deialog cydsyniad defnyddiwr, dim caniatâd VPN. Arolygu ar amserydd yw'r dewis arall y mae pobl yn troi ato, ac mae'n llosgi batri tra'n dal i golli trosglwyddiad byrrach na'r cyfwng, sef yn union y trosglwyddiad y mae defnyddiwr yn ei adrodd.

Yr hyn na all yr ateb ei ddweud wrthych o hyd

Nid oes yr un o'r API hyn yn adrodd a yw'r twnnel yn iach, ar ba weinydd y mae'n terfynu, nac a yw traffig ap penodol y tu mewn iddo. Gall rhwydwaith VPN fodoli heb lwybrau defnyddiadwy, a gall twnnel fesul ap eithrio'r ap sy'n gofyn y cwestiwn.

Felly cofnodwch yr hyn a welodd y prawf, nid y boolean yn unig. Cofnodwch yr adnabyddwr rhwydwaith, y trafnidiaethau a ddatganwyd ac a oedd y rhwydwaith hwnnw'n weithredol. Mae adroddiad sy'n dweud „ni chanfuwyd VPN” yn ddiwerth, tra bod un sy'n dweud bod rhwydwaith wedi datgan TRANSPORT_VPN ond bod getActiveNetwork() wedi dychwelyd Wi-Fi yn cyfeirio'n uniongyrchol at lwybro neu at restr eithrio, ac mae hynny'n atgyweiriad y gall rhywun weithio arno.

Erthyglau cysylltiedig