Eine Route, die auf Android in die Tabelle main eingetragen wird, sieht in jeder Auflistung korrekt aus und trägt den Verkehr trotzdem nicht. Der Grund ist, dass die Tabelle main nur eine von mehreren Möglichkeiten ist und nicht zuerst befragt wird. Androids Netzwerkdienst baut Policy-Regeln, die eine Routing-Tabelle anhand von Informationen auswählen, die die Zieladresse nicht enthält — die uid der Anwendung, eine Markierung am Paket, die Schnittstelle, auf der es ankam — und die Zielsuche erfolgt danach, innerhalb der Tabelle, die diese Regeln gewählt haben.

Drei Entscheidungen in fester Reihenfolge

Ein ausgehendes Paket trifft drei getrennte Entscheidungen. Erstens legt eine Policy-Regel fest, welche Routing-Tabelle gilt. Zweitens bestimmt eine Route in dieser Tabelle den nächsten Hop und die ausgehende Schnittstelle. Drittens entscheiden netfilter-Hooks, ob das Paket überlebt, verändert oder umgeleitet wird.

Die Reihenfolge zählt, weil jede Stufe nur ihre eigene Frage beantworten kann. Eine Firewall-Regel, die ein Paket akzeptiert, wählt keine Tabelle, und eine Route in einer Tabelle, die keine Regel wählt, ist wirkungslos. Viel Verwirrung um Android-VPNs entsteht daraus, dass man eine der drei Stufen repariert und keine Änderung beobachtet, weil der Fehler in einer anderen lag.

StageSelectorWhat it cannot decide
Policy ruleuid range, mark, incoming interfaceWhich route exists inside the table
Route lookupDestination prefix, longest matchWhether the packet is allowed out
Netfilter hookChain position, match conditionsWhich table was selected

Markierungen sind ein gepacktes Feld, kein Etikett in deinem Besitz

Android packt mehrere Fakten in denselben Markierungswert: welches Netz gewählt wurde, ob eine Anwendung ausdrücklich ein Netz gewählt hat, ob ein Socket vor dem VPN geschützt ist und Bits zu Berechtigungen. Der AOSP-fwmark-Header definiert dieses Layout für den aktuellen Baum, und das Layout ist eine Plattform-Interna, die sich zwischen Releases ändert.

Deshalb ist es auf Android gefährlich, einen ganzen Markierungswert mit iptables -j MARK --set-mark zu schreiben. Er fügt kein Tag hinzu; er ersetzt die Netzwerkauswahl, die das System bereits getroffen hat. Das Paket passt danach zu anderen Regeln, was je nach überschriebenen Bits so aussehen kann, als hätte das VPN zu arbeiten begonnen oder als hätte eine unbeteiligte App die Verbindung verloren.

Wenn du Markierungen anfassen musst, lies zuerst den aktuellen Wert und verwende eine Maske, sodass nur die Bits geändert werden, die du verstehst:

ip rule show
ip route show table all | head -40
ip route get 10.20.4.11

Eine Verbindungsmarkierung ist ein eigenes Objekt gegenüber einer Paketmarkierung, und keine von beiden ist eine Route. Die Markierung auf Antwortpaketen wiederherzustellen ist ein anderer Schritt als die Tabellenwahl beim Hinausgehen, weshalb einseitige Korrekturen Verbindungen erzeugen, die sich öffnen und dann hängen.

Wem die Regeln und Tabellen gehören

Androids Netzwerkdienst netd erzeugt die Regeln und die Tabellen pro Netz. Der AOSP RouteController ist der Ort, an dem diese Regeln für VPNs, physische Netze und uid-Bereiche zusammengesetzt werden, und sein Lebenszyklus hängt an Netzwerkereignissen statt an einer Konfigurationsdatei.

Daraus folgen zwei Konsequenzen. Erstens sind Prioritäten und Tabellennummern, die du auf einem Gerät findest, Build-Interna und keine Schnittstelle: gleich aussehende Nummern auf einer anderen Android-Version können etwas völlig anderes bedeuten. Zweitens wird der Zustand bei Netzwerkwechseln neu aufgebaut, sodass eine heute aus einer root-Shell eingefügte Regel nach dem nächsten Wi-Fi-Wechsel verschwunden sein kann.

Dieses Verschwinden wird oft so gemeldet, als ignoriere das System eine Route. Tatsächlich existiert die Regel, die die Tabelle ausgewählt hat, nicht mehr, und die Route in der Tabelle ist aus Sicht des Pakets nun unerreichbar. Prüfe die Regelliste, nicht die Routenliste, wenn eine funktionierende Konfiguration nach einem Reconnect aufhört zu funktionieren.

Fragen zur Hook-Reihenfolge haben keine allgemeine Antwort

Die Frage, ob iptables vor dem VPN-Routing läuft, lässt sich nicht beantworten, ohne den Paketpfad zu benennen. Ein lokal erzeugtes Paket durchläuft den output-Hook, wo eine Markierungsänderung eine Reroute-Prüfung auslöst — ein zweiter Lookup, keine rückwirkende Änderung des ersten. Ein Paket von einem per Tethering verbundenen Client durchläuft den prerouting-Pfad und wird stattdessen weitergeleitet, und die Chains, die es sehen, sind andere.

Dieselbe Regel kann also für den Verkehr einer App wirksam und für Tethering-Verkehr unsichtbar sein, und ein Zähler, der auf null bleibt, sagt dir, welchen Pfad das Paket genommen hat, nicht ob die Regel falsch ist. Nutze Zähler, um den Pfad zu bestimmen, bevor du eine Match-Bedingung änderst.

Das ist auch die Stufe, auf der ein Policy-Routing-Fehler schwer sichtbar wird. Routing in eine Tabelle, die existiert, aber das Ziel nicht enthält, erzeugt ein Netzwerk nicht erreichbar, das wie ein Firewall-Drop aussieht, während ein Firewall-Drop einen Timeout erzeugt, der wie ein Routing-Schwarzes-Loch aussieht.

Im System diagnostizieren oder es in Ruhe lassen

Für eine autorisierte Prüfung stelle vier Fakten fest, bevor du irgendetwas anfasst: die uid und das Profil der App, das Netz, das Android für sie gewählt hat, ob das VPN diese App überhaupt einschließt und ob das Problem für beide Adressfamilien besteht. Ein Ausschluss pro App erklärt sehr viele Meldungen der Art VPN funktioniert nicht ohne jeden Routingfehler.

Lies dann die Regeln, Masken und Tabellen, die tatsächlich gelten, und halte einen Netzwerkwechsel im Beobachtungsfenster. Ändert sich das Verhalten über einen Reconnect, siehst du einen verwalteten Lebenszyklus, keine fehlende Route.

Für gewöhnliche Anforderungen nutze die unterstützten Steuerungen: Einbeziehung und Ausschluss pro App in der VPN-Anwendung und die eigene Netzauswahl der Plattform für alles, was einen bestimmten Pfad braucht. Muss eine privilegierte Integration wirklich mit der Routing-Maschinerie zusammenarbeiten, ziele auf die Implementierung der exakten Android-Version, die du unterstützt, und pflege ihren Lebenszyklus über die Komponente, der sie gehört. Plattform-Chains zu flushen oder eine Regel mit hoher Priorität einzufügen macht aus einer Diagnose einen zweiten Netzwerkmanager, und das Telefon wird sich entsprechend verhalten.

Ähnliche Artikel