När emulatorn inte når en byggserver som webbläsaren på värddatorn öppnar utan problem, är den användbara frågan inte om VPN:en fungerar. Frågan är vilken av två mekanismer gästen saknar. Den virtuella enheten kör sin egen nätverksstack bakom emulatorns NAT, och dess resolverlista är en kopia som togs vid start, så en tunnel som kommer upp efteråt ändrar värddatorns väg utan att ändra vad gästen frågar om. Att förstå de två lagren förklarar nästan varje variant av problemet.

Gästen är en egen stack bakom en fast NAT

QEMU:s användarlägesnätverk placerar gästen på 10.0.2.15 med gateway på 10.0.2.2 och DNS-tjänsten på 10.0.2.3 till 10.0.2.6. Utgående trafik från gästen vidarebefordras inte av värddatorns kärna; den översätts till sockets på värdsidan, en per gästanslutning, och dessa sockets lämnar värddatorns adressutrymme. Det är därför en gästanslutning ärver värddatorns routingbeslut i det ögonblick den skapas, och därför gästen inte har någon post i routingtabellen som namnger din tunnel.

Samma mekanism ger gästen en användbar nödutgång. 10.0.2.2 är ett alias för värddatorns loopback-gränssnitt, så en tjänst som lyssnar på 127.0.0.1 på laptopen går att nå från gästen på den adressen. Allt som klienten bara exponerar på loopback går att nå den vägen, och det är grunden för proxyupplägget som beskrivs längre ner.

Det gästen inte kan är att observera värddatorns nätverk som om det vore dess eget namespace. Det finns ingen brygga, ingen delad routingtabell och ingen ärvd resolver, bara NAT-tjänsten som tar emot paketen och den snapshot som startaren tog när den virtuella enheten startade.

DNS är en snapshot, inte en levande bild

Vid start läser emulatorn värddatorns resolverlista och ger gästen upp till fyra servrar, exponerade på adresserna 10.0.2.3 till 10.0.2.6. Om tunneln var nere i det ögonblicket innehåller snapshoten den publika resolver som laptopen använde, och gästen fortsätter fråga den hela sitt liv. Publika namn löses, interna namn misslyckas, och alla symtom pekar på VPN:en medan det verkligt inaktuella värdet är en resolverlista som fångades några minuter innan tunneln kom upp.

Ordningskorrigeringen är alltså inte folklore. Anslut tunneln först, starta sedan om emulatorn, och föredra kallstart framför återställning av en snapshot, eftersom en quick-boot-avbildning kan komma tillbaka med resolver- och routingtillståndet den sparade tidigare. Om du vill se vad gästen använder nu, fråga enheten och inte värddatorn:

adb shell dumpsys connectivity | grep -i -A2 dns
adb shell ping -c 1 build.internal.example

Emulatorn accepterar också en explicit resolver vid start, vilket är användbart när du vet exakt vilken server gästen ska använda och farligt när den servern är publik:

emulator -avd Pixel_API_34 -dns-server 203.0.113.53

En publik resolver har ingen kopia av en intern zon, så att låsa en gör ett ordningsproblem till ett bestående fel. Om profilen skjuter ut privat DNS, låt tunneln leverera den och kallstarta gästen i stället för att hårdkoda en adress.

Routingen följer värddatorn vid anslutningstillfället

Eftersom gästanslutningar blir sockets på värddatorn fattas routingbeslutet när socketen skapas. Tunnel uppe före begäran betyder att begäran går ut genom tunneln, underställd profilens rutter. En split-tunnel-profil som bara bär utvalda prefix lämnar gärna ditt privata subnät utanför, så nåbarheten till värden är en hypotes om gästen, inte ett resultat. Befintliga gästanslutningar behåller den väg de skapades med, och därför fixar en klient som återansluter inte alltid en nedladdning som hängt sig i emulatorn.

Verifieringen hör hemma på värddatorns gränssnitt, inte i gästens statistik:

sudo tcpdump -ni tun0 'host 203.0.113.10'

Om gästens begäran dyker upp på tunnelgränssnittet fungerar routingen och problemet ligger ovanför. Om den dyker upp på det fysiska gränssnittet täcker profilen inte det prefixet, och ingen omkonfigurering på gästsidan ändrar det.

När klienten bara erbjuder en loopback-proxy

Vissa kommersiella klienter skapar ingen systemtunnel alls. De exponerar en HTTP- eller SOCKS-lyssnare på 127.0.0.1 och förväntar sig att applikationerna använder den. Gästen kan inte se den socketen direkt, men emulatorn kan bli tillsagd att använda den, antingen via de utökade kontrollerna (Settings, sedan Proxy, manuellt läge, värd 127.0.0.1 och porten som klienten skriver ut) eller vid start:

emulator -avd Pixel_API_34 -http-proxy http://127.0.0.1:8080

Kopiera porten från klientens fönster; en gissad port misslyckas tyst och ser ut som en trasig tunnel. Tänk på vad detta täcker: en HTTP-proxyinställning respekteras av applikationer som känner till proxy, och råa sockets ignorerar den helt. Om arbetslasten är en native binär som öppnar sina egna anslutningar är proxyvägen inte likvärdig med en tunnel och jämförelsen måste göras uttryckligen.

Bevisa resultatet inifrån gästen

Separera uppslagning från routing med två tester i samma session. Ett namn som misslyckas medan den numeriska adressen svarar är ett DNS-snapshotproblem, och lösningen är ordning eller en explicit resolver. Om båda misslyckas pekar det på routing eller policy, och nästa kontroll är om appen körs i en arbetsprofil med egna nätverksbegränsningar.

Till sist, vet vilken gäst du testar på. Mycket gamla emulatoravbildningar levererades utan det tun-stöd som en VPN-klient på gästsidan behöver, så ingen profil kunde någonsin fungera där; nuvarande avbildningar har det. En klient som misslyckas på en aktuell avbildning är ett klient- eller profilproblem, och att bygga om värdens tunnel ändrar inte resultatet.

Relaterade artiklar