મોટાભાગની Android એપ્લિકેશનો VPN શોધવા માટે જે તપાસ વાપરે છે તે ઇન્ટરફેસનું નામ છે, અને તે ક્યારેય VPN તપાસ નહોતી. તે જાહેર કરે છે કે વિકાસકર્તાની અપેક્ષિત શબ્દમાળા સાથે કોઈ ઇન્ટરફેસ અસ્તિત્વમાં છે, જેનો અર્થ એક ઉપકરણ પર OpenVPN અને બીજા પર સંપૂર્ણ અસંબંધિત કંઈક છે. ping એ જ પ્રકારનો પુરાવો છે: તે સાબિત કરે છે કે એક ગંતવ્યે જવાબ આપ્યો, એ નહીં કે ટનલે પેકેટ વહન કર્યું. પ્લેટફોર્મ ખરેખર જે આપે છે તે નેટવર્કનો સમૂહ અને દરેક જે ટ્રાન્સપોર્ટ જાહેર કરે છે તે છે, અને તે અલગ જવાબ સાથેનો અલગ પ્રશ્ન છે.

ભ્રમ: જો tun0 હોય તો VPN ચાલુ છે

Androidની VPN એપ્લિકેશનો VpnService અમલીકરણો છે જે સિસ્ટમને tun ફાઇલ ડિસ્ક્રિપ્ટર આપે છે. ઇન્ટરફેસનું નામ તેને બનાવનાર પાસેથી આવે છે: OpenVPN સામાન્ય રીતે tun0 બનાવે છે, PPTP અને L2TP ppp0 બનાવે છે, WireGuard તેના ઇન્ટરફેસનું નામ ટનલ પરથી રાખે છે, અને IPsec ટનલ કદાચ પરંપરાગત નામ જ બતાવે નહીં. તેથી /proc/net/dev વાંચવું કે NetworkInterface ઑબ્જેક્ટની ગણતરી કરવી એ પરંપરા શોધે છે, હકીકત નહીં.

ભૂલની બંને દિશાઓ જીવંત છે. ઉપકરણમાં વપરાશકર્તાના VPN સાથે કોઈ સંબંધ ન હોય તેવી સ્થાનિક ટનલ માટે tun0 હોઈ શકે, અને સંપૂર્ણ સ્વસ્થ WireGuard ટનલ ફક્ત tun0 શબ્દમાળા જાણતી તપાસ માટે અદૃશ્ય હોઈ શકે. એક જ ફંક્શનમાં ખોટા ધનાત્મક અને ખોટા ઋણાત્મક પરિણામો તેને નિદાન તરીકે નકામું બનાવે છે, કારણ કે ‘કોઈ VPN મળ્યું નથી’ કહેતું સપોર્ટ ટિકિટ કોઈપણ દિશામાં વિશ્વસનીય નથી.

પ્રવેશ પણ સાંકડો થયો છે. નવીન Android આવૃત્તિઓ મર્યાદિત કરે છે કે સામાન્ય એપ્લિકેશન /procમાંથી શું વાંચી શકે, તેથી Android 8 પર કામ કરતી નામ-આધારિત તપાસ કોઈ કોડ ફેરફાર વિના પછીના ઉપકરણ પર ખાલી સૂચિ પરત કરી શકે છે. જ્યારે તપાસ ચૂપચાપ ખુલ્લી બાજુ નિષ્ફળ જાય છે, ત્યારે એપ્લિકેશન તારણ કાઢે છે કે જે હાર્ડવેર પર ટનલ ઠીક છે ત્યાં VPN નથી.

ભ્રમ: સફળ ping એટલે ટનલ ટ્રાફિક વહન કરે છે

આંતરિક હોસ્ટને ping ત્યારે સફળ થાય છે જ્યારે તે હોસ્ટ સુધીનો માર્ગ અસ્તિત્વમાં હોય. વિભાજિત ટનલિંગમાં હોસ્ટ Wi-Fi દ્વારા પહોંચી શકાય તેવું હોઈ શકે જ્યારે ટનલ ચાલુ હોય અને સંપૂર્ણપણે બીજું કંઈક કરતી હોય. પ્રતિ-એપ VPNમાં ping કરતી એપ્લિકેશન ટનલમાંથી બાકાત હોઈ શકે, તેથી ICMP પડઘો તેની બહાર નીકળે છે અને પાછો આવે છે, જે તપાસ ધારે છે તેનાથી વિરુદ્ધ સાબિત કરે છે.

ICMP અને TCP પણ અલગથી ફિલ્ટર થાય છે. જે ટનલ પડઘો વિનંતીઓને મંજૂરી આપે છે પણ સેવાને જરૂરી TCP પોર્ટ છોડી દે છે તે ping કસોટી પાસ કરશે અને એપ્લિકેશનમાં નિષ્ફળ જશે, અને તે ઉપકરણની ગુણધર્મ નહીં પણ સામેની બાજુનો ફાયરવૉલ નિયમ છે. સફળ pingનું એકમાત્ર પ્રામાણિક વાંચન એ છે કે આ ગંતવ્યે આ ક્ષણે આ પ્રોટોકૉલને જવાબ આપ્યો.

પ્લેટફોર્મ ખરેખર શું જાહેર કરે છે

API 21થી, ConnectivityManager.getAllNetworks() સિસ્ટમને જાણ હોય તેવા દરેક નેટવર્ક પરત કરે છે, અને getNetworkCapabilities(network) તે નેટવર્ક શું જાહેર કરે છે તે જણાવે છે. VPN નેટવર્ક TRANSPORT_VPN વહન કરે છે. બધા નેટવર્ક પર લૂપ કરવાથી એક પ્રશ્નનો જવાબ મળે છે: આ ઉપકરણ પર અત્યારે કોઈ VPN ચાલુ છે?

બીજા, વધુ સાંકડા પ્રશ્ન માટે અલગ કૉલ જોઈએ. getActiveNetwork() તે નેટવર્ક પરત કરે છે જે એપ્લિકેશનનો ટ્રાફિક અત્યારે વાપરશે, અને તેના પર એ જ ક્ષમતા તપાસવાથી જવાબ મળે છે: શું મારો ટ્રાફિક VPNમાંથી પસાર થશે? બંને અસહમત હોઈ શકે છે, અને તે અસહમતિ માહિતીપ્રદ છે. ચાલુ પણ સક્રિય ન હોય તેવું VPN પ્રતિ-એપ રાઉટિંગ કે વિભાજિત-ટનલ રૂપરેખાંકન તરફ ઇશારો કરે છે, ખૂટતી ટનલ તરફ નહીં.

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

બંને કૉલનું રક્ષણ કરો. સૂચિબદ્ધ કરવા અને પૂછવા વચ્ચે અદૃશ્ય થયેલા નેટવર્ક માટે ક્ષમતાઓ null હોઈ શકે, અને હેન્ડઓવર દરમિયાન સક્રિય નેટવર્ક null હોઈ શકે. NET_CAPABILITY_NOT_VPN બીજી દિશામાં ઉપયોગી છે, એ સ્થાપિત કરવા માટે કે નેટવર્ક ચોક્કસપણે ટનલ નથી, ફક્ત VPN ટ્રાન્સપોર્ટ ફ્લેગ ખૂટે છે એમ નહીં.

NetworkInfo API સાથે એ જ ભ્રમ હતું

NetworkInfo સાથે ConnectivityManager.TYPE_VPN આ તપાસની બીજી પેઢી છે, અને તે કારણસર અપ્રચલિત છે. આધુનિક આવૃત્તિઓમાં ટનલ જોડાયેલી હોય ત્યારે પણ VPN માટે પરત કરાયેલ ઑબ્જેક્ટ null હોઈ શકે, તેથી nullને ‘VPN નથી’ ગણતો કોડ જે ઉપકરણોમાં જવાબ સૌથી વધુ મહત્ત્વનો છે ત્યાં ચૂપચાપ ખોટું ઋણાત્મક જાહેર કરે છે.

સામાન્ય રીતે તેની સાથે આવતું પ્રસારણ પણ સારું નથી. CONNECTIVITY_CHANGEને VPN સંક્રમણો ચૂકી જવાનો દસ્તાવેજી ઇતિહાસ છે, જેમાં એવા બિલ્ડ પણ છે જ્યાં તે દરેક નેટવર્ક ફેરફારે નહીં પણ ફક્ત VPN જોડાય કે છૂટે ત્યારે જ ચાલુ થતું. તેના પર બનેલો શ્રોતા એવું સ્થિતિ ચલ બનાવે છે જે આગલા સંપૂર્ણ પુનઃજોડાણ સુધી પ્લેટફોર્મના દૃશ્યથી દૂર જાય છે.

પોલિંગને બદલે કૉલબૅક પર પ્રતિક્રિયા આપો

TRANSPORT_VPN માંગતું અને NET_CAPABILITY_NOT_VPN દૂર કરતું NetworkRequest નોંધો, પછી તે વિનંતી સાથે registerNetworkCallback બોલાવો. પછી onAvailable અને onLost તમને જણાવે છે કે જાહેરાત ક્યારે બદલાય છે, અને તે જ ઘટના છે જે તમારા માટે ખરેખર મહત્ત્વની છે. ઘટક બંધ થાય ત્યારે કૉલબૅકની નોંધણી રદ કરો, નહીંતર એપ્લિકેશન મૃત સ્ક્રીનનો સંદર્ભ રાખે છે અને કૉલબૅક ચાલુ રહે છે.

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

આને ACCESS_NETWORK_STATE જોઈએ, જે સામાન્ય પરવાનગી છે: root નહીં, વપરાશકર્તા સંમતિ સંવાદ નહીં, VPN પરવાનગી નહીં. ટાઇમર પર પોલિંગ એ વિકલ્પ છે જે તરફ લોકો પાછા ફરે છે, અને તે બેટરી બાળે છે અને તેમ છતાં અંતરાલ કરતાં ટૂંકું સંક્રમણ ચૂકી જાય છે, જે બરાબર એ જ સંક્રમણ છે જે વપરાશકર્તા જાહેર કરે છે.

જવાબ હજી પણ તમને શું ન કહી શકે

આમાંથી કોઈ પણ API જાહેર કરતું નથી કે ટનલ સ્વસ્થ છે કે નહીં, તે કયા સર્વર પર સમાપ્ત થાય છે, કે ચોક્કસ એપ્લિકેશનનો ટ્રાફિક તેની અંદર છે કે નહીં. VPN નેટવર્ક વાપરી શકાય તેવા માર્ગ વિના પણ અસ્તિત્વમાં હોઈ શકે, અને પ્રતિ-એપ ટનલ પ્રશ્ન પૂછતી એપ્લિકેશનને બાકાત કરી શકે.

તેથી તપાસે શું જોયું તે નોંધો, ફક્ત બુલિયન નહીં. નેટવર્ક ઓળખકર્તા, જાહેર કરેલા ટ્રાન્સપોર્ટ અને તે નેટવર્ક સક્રિય હતું કે નહીં તે લોગ કરો. ‘કોઈ VPN મળ્યું નથી’ કહેતો અહેવાલ નકામો છે, જ્યારે નેટવર્કે TRANSPORT_VPN જાહેર કર્યું પણ getActiveNetwork()એ Wi-Fi પરત કર્યું એમ કહેતો અહેવાલ સીધો રાઉટિંગ કે બાકાત-સૂચિ તરફ ઇશારો કરે છે, અને તે એવું સુધારણું છે જેના પર કોઈ કામ કરી શકે.

સંબંધિત લેખો