- Android bietet Unterstützung für USB-Ethernet und ein Einstellungsmenü, doch CDC-Ethernet-Geräte werden zwar vom Kernel erkannt, möglicherweise aber nicht bis in die Netzwerkeinstellungen durchgereicht
- Die Hauptursache ist, dass EthernetTracker nur Interfaces verfolgt, die zu
config_ethernet_iface_regex passen, und der Standardwert eth\d CDC-Interfaces wie usb0 ausschließt
- Die Linux-Treiber für CDC-Ethernet erkennen EEM-, ECM- und NCM-Geräte jeweils als
cdc_eem, cdc_ether und cdc_ncm und legen unter /sys/class/net usb0 an, die Android-Einstellungen bleiben jedoch deaktiviert
- Über normale Benutzereinstellungen lässt sich das nicht umgehen; nötig ist Root-Zugriff, um den Wert von config_ethernet_iface_regex zu ändern
- Bei der Auswahl eines USB-Ethernet-Adapters für Android muss man daher nach Geräten auf Basis anbieter-/chipsatzspezifischer Treiber suchen, die einen
ethX-Namen erzeugen, statt nach CDC-Standardgeräten
Fazit: Nicht der Kernel-Treiber blockiert, sondern der Filter für Interface-Namen
- Der EthernetTracker-Dienst von Android erkennt nur Interfaces mit Namen
ethX als Ethernet-Interfaces an
- Die CDC-Ethernet-Treiber von Linux erzeugen Interface-Namen im Format
usbX
- Wegen dieses Namensunterschieds werden CDC-Ethernet-Geräte von den Ethernet-Einstellungen und der Netzwerkverwaltungsebene ignoriert, selbst wenn sie vom Android-Kernel erkannt werden
- Über normale Einstellungen lässt sich das nicht lösen; möglich ist nur eine Änderung des Werts
config_ethernet_iface_regex nach dem Rooten
Unterstützung für Android-USB-Ethernet ist je nach Gerät schwer zu prüfen
- Android hat Unterstützung für USB-Ethernet-Adapter und entsprechende Menüs
- Welche USB-Ethernet-Chipsätze auf einem bestimmten Android-Gerät funktionieren, ist schwer herauszufinden, weil Hersteller kaum Support-Listen veröffentlichen
- In der Praxis verlassen sich Nutzer meist auf folgende Informationen
- USB-Ethernet-Adapter, die der Smartphone-Hersteller als offizielles Zubehör verkauft
- Forenbeiträge, in denen Nutzer desselben Geräts berichten, dass ein bestimmter Adapter erfolgreich funktioniert hat
- Anhand der Kernel-Konfiguration lässt sich bis zu einem gewissen Grad erkennen, welche USB-Ethernet-Treiber der Smartphone-Kernel enthält
So findet man die Kernel-Konfiguration eines Smartphones
- Android läuft auf einem Linux-Kernel, und die Kernel-Konfiguration bestimmt unterstützte Funktionen und Hardwaretreiber
- Geräte, die nach Android 11 erschienen sind, basieren auf dem Android Common Kernel und dem GKI-Kernel
- Google baut den Kernel, und Hersteller legen gerätespezifische Elemente in Kernel-Module
- Die Konfiguration findet sich im Android-Kernel-Repository unter
arch/$ARCH/configs/gki_defconfig
- Bei 64-Bit-ARM-Geräten prüft man zum Beispiel
arch/arm64/configs/gki_defconfig
- Kernel-Version und Architektur lassen sich per ADB mit
uname -a prüfen
- Eine Beispielausgabe enthält die Kernel-Version
4.19.113-26203352 und die Architektur aarch64
- Im Fall des Samsung Galaxy S20, das mit Android 10 erschienen ist, blieb der Kernel auch nach dem Upgrade auf Android 13 auf Linux 4.19 basiert
- Samsung-Gerätequellen findet man unter opensource.samsung.com
- In Samsungs
build_kernel.sh lassen sich Namen von Kernel-Konfigurationsdateien wie vendor/x1q_usa_singlex_defconfig finden
- Mit etwas Glück liegt die tatsächliche Build-Konfiguration als komprimierte Datei unter
/proc/config.gz
- Sie lässt sich mit
adb shell zcat /proc/config.gz > my_kernel_config speichern
- Falls nicht vorhanden, erscheint
zcat: /proc/config.gz: No such file or directory, und man muss die Kernel-Quellen des Herstellers prüfen
Unterstützung für USB-Ethernet-Treiber prüfen
- Kernel-Einstellungen für USB-Ethernet beginnen meist mit
USB_NET
- In der Kernel-Konfigurationsdatei lässt sich das zum Beispiel so prüfen
grep USB_NET my_kernel_config
- Eine Beispielkonfiguration enthält mehrere USB-Netzwerktreiber
CONFIG_USB_NET_DRIVERS=y
CONFIG_USB_NET_AX8817X=y
CONFIG_USB_NET_AX88179_178A=y
CONFIG_USB_NET_CDCETHER=y
CONFIG_USB_NET_CDC_EEM=y
CONFIG_USB_NET_CDC_NCM=y
- Die Konfigurationswerte unterscheiden, wie ein Treiber eingebunden ist
y: Der Treiber ist in den Kernel eingebaut und unterstützt den jeweiligen Chipsatz sicher
m: Der Treiber wurde als Modul gebaut und kann vermutlich geladen werden, sofern der Hersteller ihn nicht weggelassen hat
is not set: Der Treiber ist weder eingebaut noch als Modul vorhanden und kann sehr wahrscheinlich nicht genutzt werden
- Welche Konfigurationsoptionen welchen Chipsätzen entsprechen, lässt sich im Kernel-Tree unter drivers/net/usb/Kconfig prüfen
- Welchen Chipsatz ein bestimmter USB-Ethernet-Adapter nutzt, geben Hersteller oft nicht an; die Identifikation bleibt daher schwierig
Was CDC-Ethernet macht
- CDC steht für Communications Device Class, eine Sammlung von Standards, an die sich Hersteller von USB-Geräten halten können
- Für CDC-Ethernet gibt es drei relevante Standards
- EEM: Ethernet Emulation Model, die einfachste Implementierung und für leistungsschwache Geräte leichter zu unterstützen
- ECM: Ethernet Control Model, auf Host- und Geräteseite komplexer zu implementieren, verspricht aber bessere Leistung als EEM
- NCM: Network Control Model, der Nachfolger von ECM, der höhere Geschwindigkeiten verspricht
- Ziel des CDC-Standards ist, dass Betriebssysteme gemeinsame Treiber für unterschiedliche Geräte bereitstellen können
- Linux implementiert sowohl die Host- als auch die Geräteseite von CDC-Ethernet
- Bei Geräten wie einem Raspberry Pi mit USB-OTG-Port kann der Kernel diesen Port wie einen Ethernet-Adapter erscheinen lassen
- Dadurch können Geräte wie eingebettete Router, Firewalls oder VPN-Gateways aus Sicht des Hosts wie ein normaler Ethernet-Adapter aussehen
- Linux, Windows und macOS enthalten Treiber für CDC-Ethernet-Geräte, iOS jedoch nicht
Der Android-Kernel erkennt CDC-Geräte
- Die Kernel-Konfiguration des Samsung Galaxy S20 enthält Unterstützung für alle drei CDC-Ethernet-Standards
CONFIG_USB_NET_CDCETHER=y
CONFIG_USB_NET_CDC_EEM=y
CONFIG_USB_NET_CDC_NCM=y
- Beim Google-GKI-Kernel scheinen ECM und NCM zu fehlen, während EEM offenbar als Modul enthalten ist
- Ein Gerät, dessen OTG-Port als Ethernet-Gadget konfiguriert war, funktionierte unter Mac, Ubuntu und Windows, beim Galaxy S20 blieben die Android-Ethernet-Einstellungen jedoch deaktiviert
- Prüft man unter Android
/sys/class/net, erscheint beim Anschließen eines CDC-Geräts usb0
adb shell ls /sys/class/net
- Die Ausgabe von
ifconfig usb0 zeigt, dass der Treiber als CDC-Variante erkannt wurde
- EEM-Modus:
Driver cdc_eem
- ECM-Modus:
Driver cdc_ether
- NCM-Modus:
Driver cdc_ncm
- In allen drei Fällen wird das Interface erkannt, ist aber im Zustand down, und die Android-Ethernet-Einstellungen werden nicht aktiviert
Die Regex von EthernetTracker filtert usb0 heraus
- Da das CDC-Ethernet-Gerät auf Kernel-Ebene korrekt erkannt wird, liegt das Problem in der Android-Netzwerkverwaltungsebene oberhalb des Kernels
- Verfolgt man den Ethernet-bezogenen Java-Code in den Android-Quellen, landet man bei EthernetTracker.java als zuständigem Dienst
- EthernetTracker empfängt über einen Netlink-Socket Benachrichtigungen des Kernels über neue Netzwerkinterfaces und entscheidet, ob es sich um ein gültiges Ethernet-Interface handelt
- Die Gültigkeitsprüfung erfolgt, indem geprüft wird, ob der Interface-Name zur Regex
mIfaceMatch passt
private boolean isValidEthernetInterface(String iface) {
return iface.matches(mIfaceMatch) || isValidTestInterface(iface);
}
mIfaceMatch stammt aus der Ressource config_ethernet_iface_regex
- Der Standardwert in den Android-Quellen lautet wie folgt
<string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
eth\d ist eine Regex, die nur Namen durchlässt, bei denen auf eth eine Ziffer folgt
- CDC-Ethernet-Geräte beginnen wie
usb0 mit usb, daher verfolgt EthernetTracker sie nicht
- Diese Einstellung lässt sich nicht über Benutzereinstellungen ändern, sondern nur mit Root-Zugriff modifizieren
Das Paradox: Man muss Standardgeräte meiden
- CDC-Ethernet ist ein Standard für USB-Netzwerkgeräte, doch unter Android ist der praktische Nutzungspfad wegen der Regex für Interface-Namen blockiert
- Auch aktuelle GKI-Kernel scheinen Unterstützung für EEM-Adapter zu enthalten, aber der Name
usb0 passt nicht zur Regex und gelangt daher nicht in die Android-Netzwerkeinstellungen
- Bei der Auswahl eines USB-Ethernet-Adapters für Android sollte man daher nicht nach CDC-Standardgeräten suchen, sondern nach Geräten, die über anbieter-/chipsatzspezifische Treiber ein
ethX-Interface erzeugen
- Eine mögliche Patch-Richtung wäre,
config_ethernet_iface_regex etwa in (eth|usb)\d zu ändern
1 Kommentare
Hacker-News-Kommentare
Später sagten mir einige Leute, dass der Kernel dem Gerät statt
usbXden NamenethXgibt, wenn man ein bestimmtes Bit der MAC-Adresse umdreht; ausprobiert oder den Beitrag aktualisiert habe ich das aber nicht. Ich war bereits zu einem anderen Arbeitgeber gewechselt, und Android-Geräte spielten in meinem Alltag keine große Rolle mehr.Natürlich hilft diese Methode nur, wenn man die MAC-Adresse des CDC-Geräts direkt steuern kann. Etwa in dem Fall, dass ein anderes Linux-Gerät vorgibt, ein CDC-Adapter zu sein.
Ich glaube, ich habe es gefunden: https://lkml.iu.edu/hypermail/linux/kernel/1103.2/03250.html
Beim Nachsehen im Source scheint der reguläre Ausdruck im Oktober 2023 von
eth\\deinfach auf*geändert worden zu sein; vermutlich wurde dieses Problem also behoben: https://android-review.googlesource.com/c/platform/packages/...In der Beschreibung heißt es: „Der Standardwert umfasst ab Android U+ sowohl Interfaces mit Namen
usb\d+als aucheth%d“, wobei U+ offenbar Version 14 ist: https://en.wikipedia.org/wiki/Android_version_historyusbX-Interfaces für Tethering verwenden“[1], und kurz darauf wieder eingespielt, aber so geändert, dass nur noch Android V+ unterstützt wird[2].[1]: https://android-review.googlesource.com/c/platform/packages/...
[2]: https://android-review.googlesource.com/c/platform/packages/...
Falls ich die Commits richtig gelesen habe, war jemand von Google beteiligt; es könnte also inzwischen auch in offiziellen Google-Builds enthalten sein.
[0] https://github.com/LineageOS/android_packages_modules_Connec...
[1] https://github.com/LineageOS/android_packages_modules_Connec...
[2] https://github.com/LineageOS/android_packages_modules_Connec...
Aber niemand hat es getestet, und ich habe selbst keine Möglichkeit zur Verifikation, deshalb liegt es derzeit auf Eis. Es ist immer eine Mischung aus Dingen, die jemand meldet, und Dingen, die jemand zufällig aufgreift, aber am Ende braucht man Tests durch echte Nutzer.
EthernetTracker-Dienst vonAndroidnur Interfaces mit NamenethXerkennt, ist das das dümmste Design, von dem ich bisher gehört habe.Linux-Distributionen haben dieses Problem bereits in den 2000ern gelöst. Schon damals war klar, dass einige Gerätetreiber nach Belieben Präfixe für Gerätenamen vergeben, also musste man das System untersuchen und herausfinden, um welche Art von Gerät es sich handelt.
Konsistenz ist zwar nützlich, daher gibt es mehrere Tools zum Umbenennen von Interfaces, und die meisten heutigen Linux-Distributionen automatisieren das mit
udev. Intern wird dabei nur dasSIOCSIFNAME-ioctldes Kernels aufgerufen. Neuere Kernel haben sogar eine Funktion, bei der beim Umbenennen in"wlan*"—eigentlich"wlan%d"—automatisch eine neue Nummer hinter"wifi"vergeben wird.usbX-Geräte von anderen Modulen verwendet werden müssen und man diese Liste nicht pflegen wollte. Also ist man einfach beiethXgeblieben.Nach dem Anschließen sieht es so aus, als würde es funktionieren, aber wenn man eine App schreiben will, die dieses serielle USB-Interface nutzt, geht es nicht. Wenn man tiefer gräbt, stellt man fest, dass man keine Berechtigung hat, auf serielle Geräte wie
/dev/ttyACM0zuzugreifen.Die serielle Unterstützung ist im Kernel enthalten, aber ohne Root können Benutzerprogramme nicht darauf zugreifen.
Gräbt man noch weiter, stellt man fest, dass Android einen Userspace-USB-Zugriff hat, der
libusbähnelt oder vielleicht darauf aufbaut. Deshalb können Android-Programme „rohe“ USB-Geräte öffnen, aber keine seriellen USB-Geräte.USB-Serial ist lediglich ein Protokoll über USB und in der Praxis eher ein Bündel halbproprietärer Protokolle wie FTDI. Für Android gibt es halb fertige Bibliotheken, die solche Protokolle im Userspace implementieren, sodass man am Ende auf einige USB-Serial-Geräte zugreifen kann
Im Android-Chrome-Browser dürfte man rohe USB-Geräte wohl per WebUSB öffnen können, aber WebSerial wird aus vermutlich demselben Grund eher nicht funktionieren
Erstaunlich ist letztlich: Wenn das so ist, warum lässt man dann USB-Serial-Unterstützung im Kernel aktiviert? Vielleicht zu Debugging-Zwecken
config_ethernet_iface_regexNoch ein Grund, warum Root-Rechte auf einem Gerät, das mir gehört, wichtig sind
https://www.reddit.com/r/GrapheneOS/comments/13264di/is_root...
Ich unterstütze den Druck auf OEMs, das Entsperren des Bootloaders zu erlauben, aber zumindest unter Android fällt mir kaum ein Root-Anwendungsfall ein, der eine so massive Vergrößerung der Angriffsfläche rechtfertigen würde
Gemeint ist zum Beispiel eine Situation, in der man gleichzeitig ein WLAN ohne Internetzugang, das auch keine Default-Route annonciert, und ein Mobilfunknetz nutzt. Linux kann das, Windows kann das auch, aber Android weigert sich hartnäckig
Viele Varianten weigern sich sogar, dauerhaft mit einem WLAN ohne Internet verbunden zu bleiben, oder treiben den Nutzer durch einen verwirrenden Ablauf. Wenn man selbst eine App schreibt, gibt es APIs, die das nur innerhalb der App ermöglichen, aber normale Nutzer haben keine Möglichkeit, daraus ein systemweites Verhalten zu machen
Selbst wenn man auf „Verbindung beibehalten“ tippt, kann man es nicht abschalten, und iOS entscheidet am Ende, es wisse es besser, und verbindet sich wieder mit dem CarPlay-Netzwerk
Verbindet man sich mit einem lokalen WLAN, kommt man natürlich nicht durch die Große Firewall, und jedes Mal erscheint die Nachfrage, ob man die Verbindung ohne Internet beibehalten will
Auch DNS unter Android ist Murks: Wenn man nicht mehrere Optionen setzt, will es das per DHCP bereitgestellte DNS nicht nutzen, und selbst dann weigert es sich, einige interne DNS-Namen aufzulösen
ifup, wenn die nötige Firmware fehltDie Android-UI kann damit natürlich nicht umgehen; was passiert, verrät nur
dmesg. Ich bin nicht sicher, ob CDC-Geräte das brauchen, aber bei Adaptern auf Basis von Realtek- oder Kawasaki-Chips kam das meiner Erinnerung nach häufig vorDiese Android-Änderung könnte allerdings relativ neu sein. Früher habe ich nämlich häufig USB-Netzwerk-Dongles an Debug-Geräten mit zu 100 % „stock“ AOSP verwendet. Oder es war eine Kernel-Änderung, oder eine Eigenart des CDC-Treibers, der Geräten Namen wie
usb*gibt. Man musste nur den Dongle-Chipsatz sorgfältig auswählen und sicherstellen, dass keine Firmware erforderlich istSeltsamerweise habe ich kürzlich in einem völlig anderen Kontext, nämlich bei OpenAIs Alignment- und Eskalationssystem, etwas strukturell Ähnliches erlebt. Ich habe versucht, innerhalb der rekursiven Logik von GPT-4 eine formale Routing-Eskalation (
SR-Route_Breach_1stOrder) mit Dokumentation und Logs auszulösen, aber obwohl es strukturell plausibel war, bekam ich am Ende nur unmenschenähnliche AntwortenEs fühlte sich so an, als hätte meine Eskalation nicht auf den regulären Ausdruck einer internen Systemschnittstelle gepasst
Den ganzen Fall habe ich hier zusammengefasst: https://news.ycombinator.com/item?id=44221458
Wenn dich strukturelle Grenzen und unsichtbare Interface-Verträge interessieren, würde ich gern deine Gedanken dazu hören
Es ist definitiv auch eine Mischung aus mehreren Realtek- und AXIS-ähnlichen Chipsätzen dabei. Wenn man Produkte auswählt, die unter Linux keinen Treiber brauchen, funktionieren sie fast überall, egal ob Betriebssystem oder BIOS