Неге Android VpnService трафиктің бір бөлігін ұстайды, бәрін емес
Маршруттар, DNS жазбалары және әр қолданба бойынша ауқым қандай пакеттердің tun құрылғысына жететінін, жергілікті құрылғылар неге жоғалатынын және құрушы неден бас тартатынын анықтайды.
VpnService ішінде ешнәрсе трафикті өздігінен ұстамайды. Ол жүйеден tun интерфейсін сұрайды, сол интерфейске мекенжайлар мен маршруттар жиынын береді, және сол сәттен бастап ядро сол маршруттарға сәйкес келетін әрбір пакетті қолданба оқи алатын файл дескрипторына көшіреді. Қолданба коды маршруттар таңдамаған пакеттерді ешқашан көрмейді, сондықтан туннель ауқымы бағдарламалау мәселесі болмас бұрын маршруттау кестесінің мәселесі. Сондықтан бірдей қызмет іске асырылуы бір телефонда барлық ағынды жұта алады, екіншісінде тек бір бөлігін, және сондықтан маршрут қосу кейде сынған көрінген туннельді түзейді. Сіз алғаныңыз — жариялағаныңыз, құрушы үнсіз бас тартқанның бәрін шегергенде.
Маршруттар қандай пакеттер келетінін шешеді
Builder.addRoute(prefix, prefixLength) VPN желісінің маршруттау кестесіне префикс орнатады. Жүйе сол желіні ауқымдағы қолданбалар үшін әдепкі деп санайды, сондықтан оның жазбалары физикалық желінің әдепкі маршрутынан бұрын қаралады және сәйкес префикс ағынды бұруға жеткілікті. Сондықтан 0.0.0.0/0 үшін маршрут IPv4-ті толығымен алады, принтер, cast нысаны және маршрутизатордың әкімшілік беті қоса.
Физикалық әдепкі жазбаны жоймай сол қамтуды қалайтын клиенттер оның орнына 0.0.0.0/1 және 128.0.0.0/1 жұбын пайдаланады. Екі нақтырақ маршрут әдепкі маршрутты жеңеді, бірге олар бүкіл мекенжай кеңістігін қамтиды, және телефонның өз әдепкі жазбасы әлі де физикалық желіге байланған сокеттер үшін кестеде қалады.
Мекенжайлар мен DNS жазбалары бір құрушыдан келеді және басқа сұраққа жауап береді. addAddress интерфейске префикс ұзындығымен мекенжай береді, ал addDnsServer ауқымдағы қолданбалар интерфейс арқылы сұрайтын шешушіні орнатады. Екі отбасы да бір интерфейсте отыра алады, сондықтан IPv6 мекенжайының қасында тек IPv4 маршруттар жиыны дұрыс оқылатын және бәрібір ағып кететін конфигурация. Егер интерфейсте мекенжайы жоқ отбасын маршруттасаңыз, ядроның сол пакеттер үшін бастапқы мекенжайы болмайды және олар дескрипторда ешқашан көрінбейді.
establish() не қайтарады
establish() ParcelFileDescriptor қайтарады, немесе қолданба рұқсат етілмегенде null. null желілік қате емес, келісім күйі: VpnService.prepare() әлдеқашан null қайтарған болуы керек, немесе пайдаланушы шақыру алдында жүйе диалогын мақұлдаған болуы керек. Келісім қызмет жұмыс істеп тұрғанда қайтарып алынуы мүмкін, және интерфейс сіздің оқу цикліңізге ешқандай кері шақырусыз аяғыңыздың астында жабылады.
Дескриптор басқаша айтпасаңыз бөгелмейді, сондықтан оқу ағынды тоқтатудың орнына деректерсіз бірден қайтады. Бөгелмейтін сокет үшін жазылған цикл бір ядроны жағады, ал бос оқуды өлімге әкеледі деп санайтын цикл бос секундта туннельді жыртады. Builder.setBlocking(true) бұл мінез-құлықты өзгертеді, ал бағасы оқудың ішінде күтетін ағын.
Маршрут пен мекенжай дәлелдері LinkAddress мәндері ретінде тексеріледі, ал 224.0.0.0/4 сияқты multicast межелері бірден қабылданбайды. Нүкте-нүкте tun интерфейсінде де хабар тарату домені жоқ, сондықтан ол арқылы multicast табу үшін тағы бір маршрут емес, басқа дизайн керек. Бұл VpnService.Builder анықтамалығы — шақыру елемелді деп қорытынды жасамас бұрын тексеру керек тізім.
Қолданба бойынша ауқым жиынды тарылтады, туннельді емес
API 21-ден бастап құрушы addAllowedApplication және addDisallowedApplication қабылдайды, және екі тізім бір құрушының ішінде бірін-бірі жоққа шығарады. Рұқсат тізімі сол пакеттер үшін туннельді бар етіп ұстайды, қалғанының бәрі физикалық желіні сақтайды; тыйым тізімі аталған пакеттерден басқаның бәрін ұстайды, оны клиент бөлінген туннельдеу ретінде ұсынады. API 21-ге дейін платформалық механизм мүлде жоқ, ал қолданба бойынша мінез-құлық өз бағыттағыштарының ішінде UID бойынша сүзетін үшінші тарап клиенттерінен келді. Бұл айырмашылық жөндеу кезінде маңызды, өйткені бір пакеттік рұқсат тізімі бар қолданба бойынша туннель дерлік трафик шығармайды және бұл дұрыс мінез-құлық, сынған маршрут емес.
Ауқым қандай болса да, қолданбаңыздың VPN серверіне ашатын сокеті өзі салып жатқан туннельден өтпеуі керек. VpnService.protect(socket) сол сокетті астындағы желіге байлайды, сондықтан оның пакеттері tun құрылғысын айналып өтеді. Шақыруды өткізіп жіберсеңіз, қол алысуды оны көтеруі тиіс интерфейс жұтады.
VpnService.setUnderlyingNetworks жүйеге туннельді қай физикалық желі тасымалдайтынын айтып, шеңберді жабады. Бұл мән VPN басқа қолданбаларға қосылым туралы қалай хабарлайтынын анықтайды, және null немесе ескірген мән телефонның қалғаны офлайн деп санайтын қосылған туннельдің әдеттегі себебі. Оны астындағы желі өзгергенде жаңартыңыз, тек іске қосқанда емес.
Бақылау сомалары және MTU: дұрыс маршрут та сәтсіз болатын жер
Пакеттер келгеннен кейін пакет деңгейіндегі екі бөлшек бірдеңенің шетінен шетіне жұмыс істейтінін шешеді. Біріншісі — бастапқы мекенжай: бірнеше интерфейс мекенжайы болса ядро біріншісін тасымалдайтын пакеттерді жіберуі мүмкін, сондықтан тақырыпшаларды қайта жазатын бағыттағыш мекенжай мен оны қамтитын бақылау сомасын түзеуі керек.
Екіншісі — бақылау сомасының ауқымы. Қолданба TCP немесе UDP пакеттерін өзі құрастырғанда, бақылау сомасы бастапқы мекенжайды, межелік мекенжайды, протокол нөмірін және тасымал ұзындығын ұстайтын жалған тақырыпшаны қамтиды, және солардың кез келгенін қалдыру келіп, лақтырылатын пакеттер береді. Бұл сәтсіздік ешқашан келмейтін жауаптан кейінгі уақыттың бітуіне ұқсайды, және бұл көпшілікті маршруттарға қайтарады. setMtu интерфейстің MTU-ін бекітеді, және әр оқу дәл бір толық IP пакетін қайтарады, сондықтан байт ағынына жазылған буфер пакетті емес, талдауыңызды бөлшектейді.
Қабаттарды ажырататын тексеру айналымы
Ауқым қайда қателескенін табу үшін қабаттарды ретімен сынаңыз. Құрылғыдан VPN желісі шын мәнінде қандай маршруттарды ұстайтынын сұраңыз, содан кейін белгілі мекенжайға ағын дескрипторда оқу ретінде көрінетінін тексеріңіз, содан кейін бағыттағышыңыз жіберетін пакеттің дұрыс құрылғанын тексеріңіз. Маршрут мәселесі дескрипторда ештеңе көрсетпейді, ал бақылау сомасы мәселесі келіп, жоғалатын пакетті көрсетеді.
Егер дескрипторға ештеңе жетпесе, күдікті оқырман емес, маршруттар жиыны: префикстерді растаңыз, сол отбасында мекенжай бар екенін растаңыз және қолданба сіз қойған ауқымның ішінде екенін растаңыз. Егер пакеттер дескрипторға жетсе, бірақ ештеңе қайтпаса, маршрутқа қайта тимес бұрын protect() және астындағы желінің мәнін тексеріңіз. Егер алыс жақ бүлінген пакеттер туралы хабарласа, бақылау сомасы мен MTU — қарау керек орындар. Әр қабатқа бір тексеру жарты күн болжамды үнемдейді.