Emulator Android și VPN pe gazdă: snapshot DNS și NAT
Guestul stă în spatele NAT-ului emulatorului și păstrează lista DNS copiată la pornire. Ridică tunelul înainte de boot, apoi testează rezolvarea din interiorul guestului.
Când emulatorul nu ajunge la un server de build pe care browserul de pe gazdă îl deschide fără probleme, întrebarea utilă nu este dacă VPN-ul funcționează. Întrebarea este care dintre cele două mecanisme îi lipsește guestului. Dispozitivul virtual rulează propria stivă de rețea în spatele NAT-ului emulatorului, iar lista sa de resolvere este o copie făcută la pornire, așa că un tunel care apare mai târziu schimbă calea gazdei fără să schimbe ceea ce întreabă guestul. Înțelegerea acestor două straturi explică aproape fiecare variantă a acestei probleme.
Guestul este o stivă separată în spatele unui NAT fix
Rețeaua QEMU în modul utilizator plasează guestul la 10.0.2.15 cu gateway la 10.0.2.2 și serviciul DNS la 10.0.2.3 până la 10.0.2.6. Traficul de ieșire al guestului nu este transmis de kernelul gazdei; este tradus în socketuri de partea gazdei, câte unul pentru fiecare conexiune a guestului, iar acele socketuri ies din spațiul de adrese al gazdei. De aceea o conexiune a guestului moștenește decizia de rutare a gazdei în momentul în care este creată și de aceea guestul nu are nicio intrare în tabela de rute care să numească tunelul tău.
Același mecanism îi oferă guestului o ieșire utilă. 10.0.2.2 este un alias pentru interfața loopback a gazdei, așa că un serviciu care ascultă pe 127.0.0.1 pe laptop este accesibil din guest la acea adresă. Orice expune clientul doar pe loopback poate fi atins pe această cale, iar aceasta este baza aranjamentului proxy descris mai jos.
Ce nu poate face guestul este să observe rețeaua gazdei ca și cum ar fi un namespace al ei. Nu există bridge, nu există tabelă de rute partajată și nu există resolver moștenit; există doar serviciul NAT care îi acceptă pachetele și snapshotul pe care lansatorul l-a făcut când dispozitivul virtual a pornit.
DNS este un snapshot, nu o vedere în timp real
La pornire emulatorul citește lista de resolvere a gazdei și îi dă guestului până la patru servere, expuse la adresele 10.0.2.3 până la 10.0.2.6. Dacă tunelul era oprit în acel moment, snapshotul conține resolverul public pe care îl folosea laptopul, iar guestul continuă să îl întrebe toată viața. Numele publice se rezolvă, numele interne eșuează, iar toate simptomele indică VPN-ul, în timp ce valoarea cu adevărat învechită este o listă de resolvere capturată cu câteva minute înainte ca tunelul să apară.
Corectarea ordinii nu este deci folclor. Conectează mai întâi tunelul, apoi repornește emulatorul și preferă o pornire la rece în locul restaurării unui snapshot, pentru că o imagine quick-boot poate reveni cu starea de resolvere și rute salvată anterior. Dacă vrei să vezi ce folosește guestul acum, întreabă dispozitivul, nu gazda:
adb shell dumpsys connectivity | grep -i -A2 dns
adb shell ping -c 1 build.internal.exampleEmulatorul acceptă și un resolver explicit la lansare, ceea ce este util când știi exact ce server trebuie să folosească guestul și periculos când acel server este public:
emulator -avd Pixel_API_34 -dns-server 203.0.113.53Un resolver public nu are copie a unei zone interne, așa că fixarea unuia transformă o problemă de ordine într-o defecțiune permanentă. Dacă profilul împinge DNS privat, lasă tunelul să îl furnizeze și pornește guestul la rece în loc să codifici o adresă.
Rutarea urmează gazda în momentul conexiunii
Deoarece conexiunile guestului devin socketuri ale gazdei, decizia de rutare este luată când socketul este creat. Tunelul activ înainte de cerere înseamnă că cererea iese prin tunel, supusă rutelor profilului. Un profil split-tunnel care transportă doar prefixe selectate îți va lăsa subrețeaua privată pe dinafară, așa că accesibilitatea gazdei este o ipoteză despre guest, nu un rezultat. Conexiunile existente ale guestului păstrează calea cu care au fost create, de aceea un client care se reconectează nu repară întotdeauna un download blocat în emulator.
Verificarea își are locul pe interfața gazdei, nu în statisticile guestului:
sudo tcpdump -ni tun0 'host 203.0.113.10'Dacă cererea guestului apare pe interfața tunelului, rutarea funcționează și problema este deasupra ei. Dacă apare pe interfața fizică, profilul nu acoperă acel prefix, iar nicio reconfigurare de partea guestului nu va schimba asta.
Când clientul oferă doar un proxy pe loopback
Unii clienți comerciali nu creează deloc tunel de sistem. Expun un listener HTTP sau SOCKS pe 127.0.0.1 și se așteaptă ca aplicațiile să îl folosească. Guestul nu poate vedea direct acel socket, dar emulatorul poate fi instruit să îl folosească, fie prin controalele extinse (Settings, apoi Proxy, mod manual, host 127.0.0.1 și portul afișat de client), fie la lansare:
emulator -avd Pixel_API_34 -http-proxy http://127.0.0.1:8080Copiază portul din fereastra clientului; un port ghicit eșuează în tăcere și arată ca un tunel stricat. Ține cont de ce acoperă asta: setarea de proxy HTTP este respectată de aplicațiile conștiente de proxy, iar socketurile brute o ignoră complet. Dacă sarcina de lucru este un binar nativ care își deschide propriile conexiuni, calea prin proxy nu este echivalentă cu un tunel și comparația trebuie făcută explicit.
Dovedește rezultatul din interiorul guestului
Separă rezolvarea de rutare cu două teste în aceeași sesiune. Un nume care eșuează în timp ce adresa numerică răspunde este o problemă de snapshot DNS, iar soluția este ordinea sau un resolver explicit. Dacă ambele eșuează, indică rutare sau politică, iar următoarea verificare este dacă aplicația rulează într-un work profile cu propriile restricții de rețea.
În final, știi pe ce guest testezi. Imaginile de emulator foarte vechi veneau fără suportul tun de care are nevoie un client VPN de partea guestului, așa că niciun profil nu putea funcționa acolo; imaginile actuale îl includ. Un client care eșuează pe o imagine actuală este o problemă de client sau de profil, iar reconstruirea tunelului gazdei nu va schimba rezultatul.