← Todos los artículos

· 3 min de lectura

Hacer andar en Linux un dispositivo que no tiene documentación

Un control USB sin soporte oficial, un capturador de paquetes y un workspace de Rust. Cómo se ataca un protocolo que nadie publicó.

RustUSBLinux

Compré un control de botones pensado para streaming. Funcionaba en Windows con el software del fabricante. En Linux, nada: el sistema lo veía como un dispositivo HID genérico y los botones no hacían absolutamente nada útil.

No había documentación del protocolo. No había SDK. El fabricante no contesta esas preguntas.

Terminé escribiendo el driver. Lo cuento porque el método sirve para cualquier integración donde la otra punta es una caja negra, y eso pasa mucho más seguido de lo que parece: una central telefónica vieja, un lector de tarjetas, una balanza industrial, un ERP sin API.

Primero mirar, después escribir

La tentación es abrir el editor. Es el error.

Lo primero es capturar tráfico real. En Linux, usbmon deja ver todo lo que entra y sale de un puerto USB, y Wireshark lo lee directo. Con el dispositivo andando en una máquina virtual con Windows, apretás botones y mirás qué paquetes salen.

Lo que buscás en esa montaña de bytes son patrones:

Eso último es el tipo de hallazgo que cambia todo el diseño del código. Y no se deduce leyendo: se deduce apretando botones y anotando.

Anotá todo, incluso lo que no entendés

En mi captura había un byte que cambiaba sin que yo tocara nada. Perdí un par de horas tratando de darle sentido hasta que entendí que era un contador de secuencia: subía solo, se reiniciaba en 255 y no significaba nada más.

Dejé eso escrito en el repositorio, en texto plano, al lado del código. No porque sea elegante, sino porque dentro de seis meses yo mismo no me voy a acordar, y porque alguien más va a querer entender por qué ese byte se ignora.

Un protocolo reconstruido sin notas es un protocolo que hay que reconstruir de nuevo.

Por qué Rust, y por qué tres crates

Elegí Rust por una razón concreta: en un driver, los errores son de bytes y de tiempo, y el compilador te saca de encima toda una familia de errores de memoria mientras peleás con los otros dos.

Lo dividí en tres partes:

  1. El protocolo, sin nada de entrada/salida. Recibe bytes, devuelve eventos. Se testea sin tener el dispositivo enchufado.
  2. El transporte, que habla con el USB de verdad.
  3. La aplicación, que traduce eventos en acciones del sistema.

Esa separación no es ceremonia. Es lo que permite tener tests de verdad: el 90 % de la lógica se prueba con bytes guardados en un archivo, sin hardware. Si todo estuviera junto, probar cualquier cosa requeriría tener el aparato enchufado, y los tests no se escribirían nunca.

Probarlo donde no lo escribiste

El driver corre en CI contra Fedora, Debian, Ubuntu y Arch. No es exceso de celo: los permisos de acceso a USB y las reglas de udev cambian entre distribuciones, y es exactamente el tipo de cosa que funciona en tu máquina y falla en la de quien lo instala.

Si vas a publicar algo que toca el sistema, probalo en más de un sistema. Es barato y te ahorra la mitad de los issues.

Lo que se lleva uno de acá

Cuando un proveedor te dice “no tiene API”, lo que casi siempre quiere decir es “no tiene API documentada”. Si hay un cliente que funciona, hay un protocolo, y un protocolo se puede observar.

No siempre conviene hacerlo: lleva tiempo, y si el fabricante cambia el firmware tenés que volver a empezar. Pero cuando la alternativa es cambiar todo el parque de equipos, un par de semanas de ingeniería inversa salen bastante más baratas.

El código está publicado con licencia MIT, por si a alguien le sirve el punto de partida.

¿Te pasa algo parecido? Contame tu caso

Flechas para moverte, Enter para elegir, Esc para cerrar