Android-emulator en host-VPN: DNS-snapshot en NAT uitgelegd
De guest zit achter de NAT van de emulator en houdt de DNS-lijst die bij het opstarten is gekopieerd. Breng de tunnel omhoog vóór het opstarten en test de resolutie daarna van binnenuit de guest.
Wanneer de emulator een buildserver niet bereikt die de browser op de host wel gewoon opent, is de nuttige vraag niet of de VPN werkt. De vraag is welk van twee mechanismen de guest ontbeert. Het virtuele apparaat draait zijn eigen netwerkstack achter de NAT van de emulator, en de resolverlijst ervan is een kopie die bij het opstarten is gemaakt, dus een tunnel die daarna opkomt verandert het pad van de host zonder te veranderen wat de guest vraagt. Inzicht in die twee lagen verklaart vrijwel elke variant van dit probleem.
De guest is een aparte stack achter een vaste NAT
QEMU's user-mode-netwerk plaatst de guest op 10.0.2.15 met een gateway op 10.0.2.2, en de DNS-dienst op 10.0.2.3 tot 10.0.2.6. Uitgaand verkeer van de guest wordt niet door de kernel van de host doorgestuurd; het wordt omgezet naar sockets aan de hostzijde, één per verbinding van de guest, en die sockets vertrekken vanuit de adresruimte van de host. Daarom erft een guestverbinding de routingbeslissing van de host op het moment dat ze wordt gemaakt, en daarom heeft de guest geen routetabelingang die jouw tunnel noemt.
Hetzelfde mechanisme geeft de guest een nuttige ontsnapping. 10.0.2.2 is een alias voor de loopback-interface van de host, dus een dienst die op 127.0.0.1 op de laptop luistert, is vanaf de guest op dat adres bereikbaar. Alles wat de client alleen op loopback aanbiedt, is zo bereikbaar, en dat is de basis van de proxyopstelling die verderop wordt beschreven.
Wat de guest niet kan, is het netwerk van de host bekijken alsof het zijn eigen namespace is. Er is geen bridge, geen gedeelde routetabel en geen overgenomen resolver, alleen de NAT-dienst die zijn pakketten aanneemt en de snapshot die de launcher nam toen het virtuele apparaat startte.
DNS is een snapshot, geen live beeld
Bij het opstarten leest de emulator de resolverlijst van de host en geeft de guest maximaal vier servers, aangeboden op de adressen 10.0.2.3 tot 10.0.2.6. Stond de tunnel op dat moment uit, dan bevat de snapshot de publieke resolver die de laptop gebruikte, en de guest blijft die zijn hele leven vragen. Publieke namen worden opgelost, interne namen falen, en elk symptoom wijst naar de VPN terwijl de echt verouderde waarde een resolverlijst is die enkele minuten voordat de tunnel opkwam is vastgelegd.
De volgordefix is dus geen folklore. Verbind eerst de tunnel, herstart daarna de emulator, en geef de voorkeur aan een koude start boven het herstellen van een snapshot, omdat een quick-boot-image kan terugkomen met de resolver- en routestatus die het eerder opsloeg. Wil je zien wat de guest nu gebruikt, vraag het dan aan het apparaat en niet aan de host:
adb shell dumpsys connectivity | grep -i -A2 dns
adb shell ping -c 1 build.internal.exampleDe emulator accepteert bij het starten ook een expliciete resolver, wat nuttig is wanneer je precies weet welke server de guest moet gebruiken en gevaarlijk wanneer die server publiek is:
emulator -avd Pixel_API_34 -dns-server 203.0.113.53Een publieke resolver heeft geen kopie van een interne zone, dus er één vastpinnen maakt van een volgordeprobleem een blijvende storing. Als het profiel private DNS pusht, laat de tunnel die leveren en start de guest koud in plaats van een adres hard te coderen.
Routing volgt de host op het moment van verbinden
Omdat guestverbindingen hostsockets worden, wordt de routingbeslissing genomen wanneer de socket wordt gemaakt. Tunnel omhoog vóór het verzoek betekent dat het verzoek via de tunnel naar buiten gaat, onderworpen aan de routes van het profiel. Een split-tunnelprofiel dat alleen geselecteerde prefixen vervoert, laat je privé-subnet rustig buiten, dus bereikbaarheid vanaf de host is een hypothese over de guest, geen resultaat. Bestaande guestverbindingen houden het pad waarmee ze zijn gemaakt, en daarom lost een client die opnieuw verbindt niet altijd een vastgelopen download in de emulator op.
De verificatie hoort op de interface van de host, niet in de statistieken van de guest:
sudo tcpdump -ni tun0 'host 203.0.113.10'Verschijnt het verzoek van de guest op de tunnelinterface, dan werkt routing en zit het probleem erboven. Verschijnt het op de fysieke interface, dan dekt het profiel dat prefix niet, en geen enkele herconfiguratie aan de gastzijde verandert dat.
Wanneer de client alleen een loopback-proxy biedt
Sommige commerciële clients maken helemaal geen systeemtunnel. Ze bieden een HTTP- of SOCKS-listener op 127.0.0.1 aan en verwachten dat applicaties die gebruiken. De guest kan die socket niet rechtstreeks zien, maar de emulator kan worden opgedragen hem te gebruiken, via de uitgebreide bediening (Settings, dan Proxy, handmatige modus, host 127.0.0.1 en de poort die de client afdrukt) of bij het starten:
emulator -avd Pixel_API_34 -http-proxy http://127.0.0.1:8080Kopieer de poort uit het venster van de client; een geraden poort faalt stil en ziet eruit als een kapotte tunnel. Bedenk wat dit dekt: een HTTP-proxyinstelling wordt gerespecteerd door applicaties die proxy kennen, en ruwe sockets negeren die volledig. Is de werklast een native binary die zijn eigen verbindingen opent, dan is het proxypad niet gelijkwaardig aan een tunnel en moet de vergelijking expliciet worden gemaakt.
Bewijs het resultaat van binnenuit de guest
Scheid resolutie van routing met twee tests in dezelfde sessie. Een naam die faalt terwijl het numerieke adres antwoordt, is een DNS-snapshotprobleem, en de oplossing is volgorde of een expliciete resolver. Falen beide, dan wijst dat op routing of beleid, en de volgende controle is of de app in een werkprofiel met eigen netwerkbeperkingen draait.
Weet tot slot op welke guest je test. Zeer oude emulator-images werden geleverd zonder de tun-ondersteuning die een VPN-client aan de gastzijde nodig heeft, dus geen enkel profiel kon daar ooit werken; huidige images hebben die. Een client die op een huidig image faalt, is een client- of profielprobleem, en de tunnel van de host opnieuw opbouwen verandert de uitkomst niet.