Android-VPN mit IPv6 läuft, doch der Browser wählt weiter IPv4
Verfolgen Sie die vier Stufen, auf denen eine private IPv6-Adresse verschwindet: Resolver, VpnService-Deklaration, Browser-Kandidatenprüfung und Routenzustellung.
Das VPN läuft, die private Weboberfläche antwortet über IPv6 von einem Laptop, und das Android-Telefon öffnet dieselbe Seite weiterhin über IPv4 oder lädt sie gar nicht. Der AAAA-Eintrag existiert. Der Tunnel meldet eine IPv6-Adresse. Im Client sieht nichts falsch aus. Vier getrennte Entscheidungen bestimmen das Ergebnis: welcher Resolver geantwortet hat, was der VpnService gegenüber Android deklariert hat, welche Adressfamilie der Browser zu versuchen bereit war und ob ein Paket den Weg hin und zurück schafft. Arbeiten Sie sie in dieser Reihenfolge ab, statt eine Default-Route hinzuzufügen und zu hoffen, dass das Symptom weiterwandert.
Schritt 1: Beweisen Sie, welcher Resolver die AAAA-Abfrage beantwortet hat
Android hat keinen einzigen DNS-Pfad. Ein VPN kann einen DNS-Server für sein Netz durchdrücken, das System kann Private DNS für Hostnamen verwenden, die es als geeignet ansieht, und Chrome kann seinen eigenen verschlüsselten Resolver aus chrome://settings/security heraus betreiben. Auf einem Telefon, bei dem der Tunnel 10.61.0.1 durchdrückt, Private DNS aber auf einen öffentlichen Anbieter zeigt, wird der Name in Ihrer privaten Zone nicht von der Maschine aufgelöst, die die Zone besitzt. Der Browser bekommt eine Antwort von einem Resolver ohne Zuständigkeit für diesen Namen und behandelt sie als fehlend, und der Fehlertext erwähnt DNS nie.
Fragen Sie den Resolver des Tunnels direkt, bevor Sie etwas anderes ändern. Die ersten beiden Befehle zeigen, welche DNS-Server Android an das aktive Netz gebunden hat und ob Private DNS im automatischen oder strikten Modus läuft; der dritte läuft von einem beliebigen Client im Tunnel, nicht vom Telefon.
adb shell dumpsys connectivity | grep -A3 "DnsAddresses"
adb shell settings get global private_dns_mode
nslookup -type=AAAA nas.lan 10.61.0.1
Schritt 2: Lesen Sie, was der VpnService tatsächlich deklariert hat
Die Android-Seite ist explizit und nicht abgeleitet. Ein VpnService.Builder fügt Adressen mit addAddress, Routen mit addRoute, DNS-Server mit addDnsServer hinzu und kann den gesamten Tunnel mit allowFamily auf eine Adressfamilie beschränken. Ein Builder, der allowFamily(AF_INET) aufgerufen und später eine IPv6-Route hinzugefügt hat, hat dem System zwei widersprüchliche Dinge gesagt, und die Familienbeschränkung ist das, was das System behält. Eine Route für fd00:61::/64 in Kombination mit einer Schnittstellenadresse in einem anderen Präfix scheitert aus einem ähnlichen Grund: die Adresse existiert, ist aber für diese Route nicht on-link.
Lesen Sie die Deklaration, statt dem Schalter in der App zu vertrauen. dumpsys netd gibt die Adressen und Routen aus, die an die tun-Schnittstelle gebunden sind, und LinkProperties pro Netz in dumpsys connectivity zeigt die DNS-Liste neben den Familien, die das Netz beansprucht.
adb shell ip -6 addr show tun0
adb shell ip -6 route show table all | grep tun0
adb shell dumpsys connectivity | grep -E "LinkAddresses|Routes"
Hat die tun-Schnittstelle eine IPv6-Adresse, passt aber keine Route zum Präfix des Dienstes, ist die IPv6-Zustellung schon defekt, bevor ein Browser im Spiel ist. Das ist ein anderer Fehler als ein Browser, der es nicht versucht, und er braucht eine andere Korrektur.
Schritt 3: Der Browser entscheidet, ob er IPv6 überhaupt versucht
Chromium nutzt nicht jeden AAAA-Eintrag, den es erhält. Sein Host-Resolver trägt IPv6-Erreichbarkeitsprüfungen und Kandidatenfilterung, die IPv6 verwerfen oder herabstufen können, wenn das Netz als unfähig gilt, es zu tragen, und der Quellcode des Resolvers zeigt diese Prüfung zusammen mit den Bedingungen darum herum. Die Logik hängt von Version und Flags ab, und genau deshalb können sich zwei Telefone am selben Tunnel unterschiedlich verhalten. Sobald Kandidaten existieren, lässt Happy Eyeballs die Familien pro Verbindung rennen, sodass ein IPv6-Pfad, der langsam antwortet, trotzdem gegen schnelles IPv4 verlieren kann.
Beobachten Sie die Entscheidung, statt sie zu erschließen. Eine über chrome://net-export aufgezeichnete und im netlog-Viewer abgespielte Sitzung zeigt jede Auflösung und die gewählte Familie; chrome://net-internals/#dns zeigt die gecachten Ergebnisse. Eine Auflösung, die nur A-Einträge für einen Namen liefert, der in Ihrem eigenen Resolver AAAA hat, deutet direkt auf diese Stufe.
Schritt 4: Prüfen Sie, ob ein Paket den Weg hin und zurück schafft
Adressauswahl ist keine Zustellung. Android hält Routing-Tabellen und Policy-Regeln pro Netz, die eine Tabelle per fwmark auswählen, sodass eine in der Haupttabelle sichtbare Route nicht automatisch die Route ist, die ein Socket nutzt. Regeln zu lesen und den Kernel zu bitten, ein Ziel für eine Quelladresse aufzulösen, trennt beides.
adb shell ip -6 rule show
adb shell ip -6 route get fd00:61::20 from fd00:61::10
Die Ausgabe von route get ist die, die die Frage beantwortet. Nennt sie tun0 und sterben Pakete weiterhin, gehen Sie zur MTU des Tunnels und zum IPv6-Weiterleiten des Gateways statt zurück zum Telefon.
Warum das Hinzufügen von ::/0 es meist schlimmer macht
::/0 hinzuzufügen ändert den Anspruch des Tunnels von einem Präfix auf jedes IPv6-Ziel. Auf dem Telefon kann das eine Erreichbarkeitsprüfung erfüllen, weil eine Testadresse außerhalb Ihres Präfixes nun routbar aussieht. Es schafft aber keine IPv6-Upstream-Kapazität am Gateway, und viele Heim-Gateways haben überhaupt keinen funktionierenden IPv6-Uplink. Das Ergebnis ist ein schwarzes Loch für öffentliches IPv6: Namen, die früher auf IPv4 zurückfielen, hängen jetzt, und die private Seite sieht vielleicht nur deshalb besser aus, weil die Prüfung etwas anderes misst.
Dazu kommt ein politischer Preis. Mit ::/0 im Tunnel verlässt der gesamte IPv6-Verkehr das Netz über das VPN, auch Verkehr, den der Netzeigentümer nie zu tragen zugestimmt hat. Behandeln Sie das als Deployment-Entscheidung mit einem benannten Verantwortlichen, nicht als Debugging-Schritt um 1 Uhr nachts.
Die Reihenfolge, die das beendet
Bestätigen Sie, dass die AAAA-Antwort von dem Resolver kommt, der die Zone hält, lesen Sie VpnService- und netd-Zustand für die tun-Schnittstelle, zeichnen Sie einen net-export-Trace auf, um zu sehen, ob Chromium den Kandidaten verworfen hat, und testen Sie dann den Weg hin und zurück mit ip -6 route get. Reparieren Sie die Schicht, die tatsächlich versagt hat, und lassen Sie die Split-Policy in Ruhe. Wenn private Namen andere Antworten brauchen als öffentliche, genau dafür ist Split Tunneling da.
Notieren Sie den Build des Telefons, die Browserversion und den Resolver, den Sie abgefragt haben. Diese drei Fakten machen aus "IPv6 is broken" etwas, das die nächste Person reproduzieren kann.