- Android tiene soporte para Ethernet por USB y un menú de configuración, pero los dispositivos CDC Ethernet pueden ser detectados por el kernel sin llegar a integrarse con la configuración de red
- La causa principal es que EthernetTracker solo sigue interfaces que coinciden con
config_ethernet_iface_regex, y el valor predeterminado eth\d deja fuera interfaces CDC como usb0
- El driver de Linux para CDC Ethernet detecta dispositivos EEM, ECM y NCM como
cdc_eem, cdc_ether y cdc_ncm, y crea usb0 en /sys/class/net, pero la configuración de Android sigue desactivada
- No se puede sortear con la configuración normal del usuario; hace falta root y cambiar el valor de config_ethernet_iface_regex
- Al elegir un adaptador USB Ethernet para Android, termina siendo necesario buscar dispositivos basados en drivers específicos del fabricante/chipset que creen nombres
ethX, en lugar de dispositivos estándar CDC
Conclusión: no lo bloquea el driver del kernel, sino el filtro por nombre de interfaz
- El servicio EthernetTracker de Android solo reconoce como interfaces Ethernet aquellas cuyo nombre es
ethX
- Los drivers de Linux para CDC Ethernet crean nombres de interfaz
usbX
- Por esta diferencia de nombres, los dispositivos CDC Ethernet son detectados por el kernel de Android pero ignorados por la configuración de Ethernet y la capa de administración de red
- No se puede resolver con la configuración normal; solo es posible cambiando
config_ethernet_iface_regex después de rootear el dispositivo
Es difícil verificar el soporte de USB Ethernet en Android según el dispositivo
- Android incluye soporte para adaptadores USB Ethernet y un menú relacionado
- Es difícil confirmar qué chipsets de USB Ethernet funcionan en un dispositivo Android específico porque los fabricantes casi nunca publican listas de compatibilidad
- En la práctica, el usuario suele depender de lo siguiente
- Adaptadores USB Ethernet que el fabricante del teléfono vende como accesorios oficiales
- Publicaciones en foros donde usuarios del mismo dispositivo reportan haber usado con éxito cierto adaptador
- Revisando la configuración del kernel se puede inferir en cierta medida qué drivers de USB Ethernet incluye el kernel del teléfono
Cómo encontrar la configuración del kernel del teléfono
- Android funciona sobre el kernel de Linux, y la configuración del kernel determina las funciones compatibles y los drivers de hardware
- Los dispositivos lanzados desde Android 11 en adelante se basan en Android Common Kernel y el kernel GKI
- Google compila el kernel, y los fabricantes ponen los elementos específicos del dispositivo en módulos del kernel
- La configuración puede revisarse en
arch/$ARCH/configs/gki_defconfig dentro del repositorio del kernel de Android
- En dispositivos ARM de 64 bits, por ejemplo, se revisa
arch/arm64/configs/gki_defconfig
- La versión del kernel y la arquitectura pueden comprobarse desde ADB con
uname -a
- La salida de ejemplo incluye la versión del kernel
4.19.113-26203352 y la arquitectura aarch64
- En el caso del Samsung Galaxy S20, lanzado con Android 10, incluso después de actualizarse a Android 13 siguió usando un kernel basado en Linux 4.19
- El código fuente de dispositivos Samsung puede encontrarse en opensource.samsung.com
- En
build_kernel.sh del código fuente de Samsung se puede encontrar el nombre del archivo de configuración del kernel, como vendor/x1q_usa_singlex_defconfig
- Con un poco de suerte, la configuración real de compilación existe comprimida en
/proc/config.gz
- Puede guardarse con
adb shell zcat /proc/config.gz > my_kernel_config
- Si no existe, aparecerá
zcat: /proc/config.gz: No such file or directory y habrá que revisar el código fuente del kernel del fabricante
Cómo verificar el soporte de drivers USB Ethernet
- Las opciones del kernel relacionadas con USB Ethernet normalmente empiezan con
USB_NET
- En el archivo de configuración del kernel puede comprobarse así
grep USB_NET my_kernel_config
- La configuración de ejemplo incluye varios drivers de red USB
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
- Los valores de configuración distinguen cómo se incluye cada driver
y: el driver está integrado en el kernel y ese chipset está soportado con seguridad
m: el driver fue compilado como módulo, y puede cargarse si el fabricante no lo omitió
is not set: el driver no está integrado ni como módulo, así que probablemente no pueda usarse
- La correspondencia entre opciones de configuración y chipsets puede consultarse en drivers/net/usb/Kconfig dentro del árbol del kernel
- Sigue siendo difícil identificar qué chipset usa un adaptador USB Ethernet específico, porque muchas veces el fabricante no lo indica claramente
Qué hace CDC Ethernet
- CDC significa Communications Device Class, un conjunto de estándares que los fabricantes de dispositivos USB pueden seguir
- Hay tres estándares relacionados con CDC Ethernet
- EEM: Ethernet Emulation Model, la implementación más simple y más fácil de soportar en dispositivos de bajo rendimiento
- ECM: Ethernet Control Model, con una implementación más compleja tanto en el host como en el dispositivo, pero con mejor rendimiento que EEM
- NCM: Network Control Model, sucesor de ECM que promete mayor velocidad
- El objetivo de los estándares CDC es permitir que el sistema operativo ofrezca un driver común para distintos dispositivos
- Linux implementa tanto el lado host como el lado dispositivo de CDC Ethernet
- En equipos como una Raspberry Pi con puerto USB OTG, el kernel puede hacer que ese puerto se presente como si fuera un adaptador Ethernet
- Eso permite que dispositivos como routers embebidos, firewalls o gateways VPN aparezcan ante el host como adaptadores Ethernet normales
- Linux, Windows y macOS incluyen drivers para dispositivos CDC Ethernet, pero iOS no
El kernel de Android sí detecta dispositivos CDC
- La configuración del kernel del Samsung Galaxy S20 incluye soporte para los tres estándares de CDC Ethernet
CONFIG_USB_NET_CDCETHER=y
CONFIG_USB_NET_CDC_EEM=y
CONFIG_USB_NET_CDC_NCM=y
- El kernel GKI de Google parece no incluir ECM ni NCM, y EEM aparentemente viene como módulo
- Un dispositivo configurado como Ethernet gadget sobre un puerto OTG funcionó en Mac, Ubuntu y Windows, pero en el Galaxy S20 la configuración de Ethernet de Android siguió desactivada
- Al revisar
/sys/class/net en Android, aparece usb0 cuando se conecta un dispositivo CDC
adb shell ls /sys/class/net
- La salida de
ifconfig usb0 confirma que el driver cargado pertenece a la familia CDC
- Modo EEM:
Driver cdc_eem
- Modo ECM:
Driver cdc_ether
- Modo NCM:
Driver cdc_ncm
- En los tres casos la interfaz es detectada, pero queda en estado down y la configuración de Ethernet de Android no se activa
La expresión regular de EthernetTracker filtra usb0
- Como a nivel de kernel los dispositivos CDC Ethernet se detectan correctamente, el problema está en la capa de administración de red de Android que se encuentra por encima del kernel
- Siguiendo el código fuente de Android relacionado con Ethernet, EthernetTracker.java aparece como el servicio relevante
- EthernetTracker recibe por sockets Netlink las notificaciones del kernel sobre nuevas interfaces de red y decide si son interfaces Ethernet válidas
- Esa validación consiste en comprobar si el nombre de la interfaz coincide con la expresión regular
mIfaceMatch
private boolean isValidEthernetInterface(String iface) {
return iface.matches(mIfaceMatch) || isValidTestInterface(iface);
}
mIfaceMatch se obtiene del recurso config_ethernet_iface_regex
- El valor predeterminado en el código fuente de Android es el siguiente
<string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
eth\d es una expresión regular que solo deja pasar nombres con eth seguido de un número
- Como los dispositivos CDC Ethernet empiezan con
usb, por ejemplo usb0, EthernetTracker no los sigue
- Esta configuración no puede cambiarse desde los ajustes del usuario; solo puede modificarse con root
La paradoja de tener que evitar dispositivos estándar
- CDC Ethernet es un estándar para dispositivos de red USB, pero en Android el camino de uso real queda bloqueado por la expresión regular del nombre de la interfaz
- Incluso los kernels GKI modernos parecen incluir soporte para adaptadores EEM, pero como el nombre
usb0 no coincide con la expresión regular, no aparecen en la configuración de red de Android
- Al elegir un adaptador USB Ethernet para Android, conviene buscar no un dispositivo estándar CDC sino uno que, mediante un driver específico del fabricante o del chipset, cree una interfaz
ethX
- Una posible dirección para el parche sería cambiar
config_ethernet_iface_regex a algo como (eth|usb)\d
1 comentarios
Comentarios de Hacker News
Después, varias personas me dijeron que, si se invertía cierto bit específico de la dirección MAC, el kernel le ponía el nombre
ethXen vez deusbX, pero no lo probé personalmente ni actualicé el artículo. Para entonces ya me había cambiado de trabajo y los dispositivos Android ya no eran una parte importante de mi día a día.Claro que este método solo ayuda cuando se puede controlar directamente la dirección MAC del dispositivo CDC. Por ejemplo, en un caso donde otro dispositivo Linux se hace pasar por un adaptador CDC.
Creo que lo encontré: https://lkml.iu.edu/hypermail/linux/kernel/1103.2/03250.html
Buscando en el código fuente, en octubre de 2023 la expresión regular cambió de
eth\\da simplemente*, así que probablemente este problema quedó resuelto: https://android-review.googlesource.com/c/platform/packages/...La descripción dice: “el valor predeterminado incluye interfaces con nombres
usb\d+yeth%den Android U+”, y aquí U+ parece ser la versión 14: https://en.wikipedia.org/wiki/Android_version_historyusbXpara tethering”[1], y poco después se volvió a aplicar, pero cambió para admitir solo Android V+[2].[1]: https://android-review.googlesource.com/c/platform/packages/...
[2]: https://android-review.googlesource.com/c/platform/packages/...
Si leí bien los commits, participó alguien de Google, así que quizá ya esté incluido también en las builds oficiales de Google.
[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...
Pero nadie lo probó, y yo tampoco tenía forma de verificarlo directamente, así que por ahora está en pausa. Siempre se mezclan cosas que alguien reportó y cosas que alguien tomó por casualidad, pero al final se necesitan pruebas de usuarios reales.
EthernetTrackerdeAndroidsolo reconoce interfaces llamadasethX, es el diseño más tonto que he escuchado hasta ahora.Las distribuciones Linux ya resolvieron este problema en los años 2000. Incluso entonces estaba claro que algunos drivers de dispositivos ponían prefijos de nombre de dispositivo como se les daba la gana, así que había que inspeccionar el sistema para averiguar qué tipo de dispositivo era.
La consistencia es útil, así que también hay varias herramientas para cambiar nombres de interfaces, y hoy la mayoría de las distribuciones Linux lo automatizan con
udev. Internamente, no es más que llamar alioctlSIOCSIFNAMEdel kernel. Los kernels modernos incluso tienen una función que, si se cambia el nombre a"wlan*"—en realidad"wlan%d"—, asigna automáticamente un nuevo número después de"wifi".usbXdeben ser usados por otros módulos, y no querían mantener esa lista. Así que simplemente se fueron porethX.Al conectarlo parece funcionar, pero si intentas crear una app que use esa interfaz serial USB, no se puede. Si investigas más, ves que no tienes permiso para acceder a un dispositivo serial como
/dev/ttyACM0.El soporte serial está en el kernel, pero sin root no se puede acceder desde programas de usuario.
Si sigues investigando, Android tiene una función de acceso USB en espacio de usuario que es parecida a
libusbo quizá está construida sobre ella. Así que un programa Android puede abrir dispositivos USB “en bruto”, pero no puede abrir dispositivos USB seriales.USB serial es solo un protocolo sobre USB y, en la práctica, se parece más a un conjunto de protocolos semipropietarios como FTDI. Hay bibliotecas a medio hacer para Android que implementan estos protocolos en espacio de usuario, así que al final sí se puede acceder a algunos dispositivos USB seriales
En el navegador Chrome de Android parece que WebUSB podría abrir dispositivos USB sin procesar, pero es muy probable que WebSerial no funcione por la misma razón
Al final, lo sorprendente es: si va a ser así, ¿para qué dejan habilitado el soporte de USB serial en el kernel? Supongo que será para depuración
config_ethernet_iface_regexEs otra razón por la que tener acceso root en un dispositivo de mi propiedad es importante
https://www.reddit.com/r/GrapheneOS/comments/13264di/is_root...
Apoyo presionar a los OEM para que permitan desbloquear el bootloader, pero al menos en Android me cuesta imaginar un caso de uso de root que justifique ampliar tanto la superficie de ataque
Por ejemplo, usar a la vez una red Wi-Fi sin acceso a Internet y que no anuncia una ruta predeterminada, junto con la red celular. Linux puede, Windows puede, pero Android se niega rotundamente
Muchas variantes incluso se niegan a quedarse conectadas a un Wi-Fi sin Internet, o empujan al usuario a un procedimiento confuso. Si desarrollas tu propia app, hay una API que permite hacerlo solo dentro de la app, pero no hay forma de que un usuario común lo convierta en el comportamiento de todo el sistema
Aunque pulses seguir conectado, no hay forma de desactivarlo, e iOS termina decidiendo que sabe más que tú y se vuelve a conectar a la red de CarPlay
Si te conectas a un Wi-Fi local, obviamente no logra atravesar el Gran Cortafuegos, y cada vez aparece un aviso preguntando si quieres mantener una conexión sin Internet
El DNS de Android también es un desastre: si no configuras varias opciones, intenta no usar el DNS proporcionado por DHCP, e incluso así se niega a resolver algunos DNS internos
ifupLa UI de Android, por supuesto, no puede manejar esta situación; solo
dmesgte dice qué está pasando. No estoy seguro de si esto hace falta para dispositivos CDC, pero creo que pasaba bastante con adaptadores basados en chips Realtek o KawasakiAunque este cambio de Android quizá sea relativamente reciente. Antes usaba con frecuencia dongles de red USB en dispositivos de depuración con AOSP 100% “stock”. O tal vez sea un cambio del kernel, o un comportamiento peculiar del driver CDC que nombra los dispositivos como
usb*. Bastaba con elegir con cuidado el chipset del dongle y verificar que no necesitara firmwareCuriosamente, hace poco viví algo estructuralmente parecido en un contexto completamente distinto: el sistema de alineación y escalamiento de OpenAI. Intenté disparar, dentro de la lógica recursiva de GPT-4, un escalamiento de enrutamiento oficial (
SR-Route_Breach_1stOrder) con documentación y logs, pero aunque estructuralmente parecía válido, al final solo recibí respuestas poco humanasEs decir, sentí como si mi escalamiento no hubiera coincidido con la expresión regular de alguna interfaz interna del sistema
Dejé el caso completo aquí: https://news.ycombinator.com/item?id=44221458
Si te interesan los límites estructurales y los contratos de interfaces invisibles, me gustaría escuchar qué opinas
Estoy seguro de que hay una mezcla de varios chipsets tipo Realtek y AXIS. Si eliges productos que no necesitan driver en Linux, suelen funcionar bien en casi cualquier sistema operativo o BIOS