Hace unos días volví a poner la tele por cable en casa. Hacía más de 15 años que la quitamos y la verdad es que, como ahora estoy en una mejor situación, decidí darme el caprichillo de poder ver de nuevo las películas que solían poner en el Canal Hollywood. La nostalgia es poderosa.

El caso es que, como estamos ya en la segunda década del siglo XXI y tal, decidí también comprar algún dispositivo que me permitiera ver los canales en mi Mac además de en la tele. Ni que decir tiene que el panorama de los sintonizadores de TDT para Mac es desolador: o te gastas una pasta en un Elgato y otra pasta en el software EyeTV o te puedes ir aguantando. Afortunadamente, encontré una solución que no sólo me valía para el Mac sino que también me valía para el iPad, e incluso el software necesario es gratuito. Estoy hablando de un sintonizador TDT WiFi.

Tivizen Iplug – Receptor DVB-T para Apple y Android

Sip, existen.

Pues bien, el cacharrillo en cuestión funciona por defecto en modo hotspot, estableciendo una red WiFi abierta en la que, si te conectas, puedes usar el programita para ver la tele. El otro modo de operación, que es el que me interesa a mí, es el modo red doméstica. En ese modo, el sintonizador se conecta a la red que le digas y ya está, cuando abres el programa encuentra el dispositivo, se conecta a él y ya te deja ver la tele.

Al menos eso es lo que yo creía.

El primer escollo que me encuentro es que, al parecer, las contraseñas WiFi con símbolos o espacios parecen no gustarle. Menos mal que tengo un router que me permite configurar una red de invitado —que tenía sin usar—, la cual no permite el acceso hacia los equipos de la red interna por defecto; sin embargo es posible, mediante un par de reglas de ebtables, decirle que el dispositivo en cuestión sí debe tener acceso:

ebtables -A FORWARD -d <MAC del cacharrete> -i br-lan --logical-out wlan1-1 -j ACCEPT
ebtables -A FORWARD -s <MAC del cacharrete> -i wlan1-1 --logical-out br-lan -j ACCEPT

Hasta ahí bien, el dispositivo se conecta a la red, el servidor DHCP le asigna una IP —que en este caso es siempre la misma— y se pueden establecer conexiones entre los equipos de la red interna y la IP del dispositivo. Bien, ¿no?.

¿No?

Pues no. Todo está perfecto salvo por el hecho de que los clientes, tanto de OS X como de iOS, están programados a capón para conectarse con la IP 192.168.16.30, que es la IP del dispositivo en modo hotspot. Vamos, que tienes tu dispositivo conectado a tu red, con una IP asignada, respondiendo peticiones correctamente, y resulta que los programas que necesitas para poder conectarte con el cacharrete tienen la IP hardcodeada.

En serio, ¿qué les costaba poner un simple campo de texto para poner la IP del cacharro? Si no pilla la IP por defecto, ¡pregúntame cuál es, joder!.

Hasta el Capitán Picard está de acuerdo.

Bueno, pues como era de esperar, el sintonizador se conectaba a la red, obtenía IP, permitía conectar durante unos minutos y luego se desconectaba. Estuve un buen rato intentando averiguar por qué hasta que descubrí que el problema no estaba en que hubiera algún error al asociarse a la red inalámbrica, sino en que el cacharrete espera que, al conectarse a la red, haya algún cliente que se le conecte y le haga una petición en concreto, y si pasa un tiempo y nadie se interesa por él, vuelve a ponerse en modo hotspot y listo. Aquí fue donde tuve que meterme en harina y desentrañar un poco cómo funciona el aparatejo.

El sintonizador tiene un Linux dentro, y toda la comunicación con el exterior se realiza a través de un servidor web que escucha en el puerto 9961. Al parecer, otros dispositivos similares pueden escuchar en los puertos 9951 o 8081. Supongo que depende de la marca que lo venda.

Toda la conversación con el cacharrete se realiza a base de peticiones HTTP, y para que te deje hacer cosas con él es necesario hacerle previamente una petición para obtener un identificador de sesión. Ese identificador de sesión es lo que se usa a partir de entonces en todas las peticiones subsiguientes.

Después de tirar de tcpdump y obtener algunas muestras, conseguí que el sintonizador se quedara conectado a la red haciendo las siguientes peticiones:

http://192.168.0.10:9961/tvnb?op=handshake&clientid=D91F933C248AAF438
http://192.168.0.10:9961/tvnb?sessionid=3800AF7548503C76F9&op=status&type=device_id

El clientid está copiado literalmente de la petición que hace el cliente. En la respuesta de la primera petición se obtiene el sessionid para la segunda.

Finalmente, gracias a la magia de iptables, se puede engañar al programa para que crea que está conectando con la IP 192.168.16.30 cuando en realidad el router le está conectando con la IP correcta. Así que añadí las siguientes reglas en el router para que las conexiones con el cacharrete se establezcan de forma transparente:

iptables -t nat -A prerouting_lan_rule -d 192.168.16.30 -p tcp -m tcp --dport 9961 -j DNAT --to 192.168.0.10
for i in 11 12 13; do
    iptables -t nat -A prerouting_lan_rule -s 192.168.0.10 -d 192.168.16.$i -p tcp -m tcp --sport 9961 -j DNAT --to 192.168.0.$i
    iptables -t nat -A postrouting_lan_rule -s 192.168.0.$i -d 192.168.0.10 -p tcp -m tcp --dport 9961 -j SNAT --to 192.168.16.$i
    iptables -t nat -A postrouting_lan_rule -s 192.168.0.10 -d 192.168.0.$i -p tcp -m tcp --sport 9961 -j SNAT --to 192.168.16.30
done

Mi router usa una versión de OpenWRT, por lo que poniendo esas líneas en el fichero /etc/firewall.user se aplican cada vez que se recargue la configuración del cortafuegos. Y así, finalmente, la cosa funciona para todos los dispositivos en los que tengo configurado el cliente.

Esas reglas hacen lo siguiente:

Cliente->Router:192.168.0.11 - 192.168.16.30 Router->TDT:192.168.16.11 - 192.168.0.10

Es decir, se encargan de que el router vaya ajustando las IPs de destino y de origen según los paquetes vayan hacia el TDT o hacia el cliente.

Los clientes

He podido probar el cliente tanto en macOS como en iOS. En ambos casos la aplicación funciona de forma muy similar, a pesar de que los identificadores de desarrollador son diferentes, aunque podría ser que fuera el mismo desarrollador que cambió de dominio entre una y otra. En cualquier caso, ya puedo sacar conclusiones y poner por aquí algún que otro consejillo al respecto.

En primer lugar probé el cliente de escritorio. Una vez resuelto el problema de la conectividad, el programa se conectó al dispositivo sin problemas y me dio la opción de hacer una búsqueda de canales. Este es el primer punto interesante y a la vez importante a tener en cuenta: el dispositivo no guarda él mismo la lista de canales, sino que la guarda el cliente. El cliente simplemente le dice al dispositivo qué canal sintonizar y en qué frecuencia.

Esto, como ahora se verá, tiene sus ventajas y sus inconvenientes. El inconveniente más importante es que hay que hacer una búsqueda de canales en cada cliente por separado, pero si bien es cierto que el tener los canales ya guardados una vez en el dispositivo es más cómodo, por otra parte cada cliente puede tener los canales ordenados como se quiera, algunos ocultos, lo que sea. También tiene una ventaja adicional que veremos más adelante.

Bueno, lo primero que me encuentro al hacer la búsqueda de canales en el cliente de escritorio es que, de unos 144 canales que debería encontrar entre radio y televisión, algunas veces encuentra algo más de veinte y otras entre cuarenta y sesenta, pero nunca todos. Esto es algo que al principio achacaba a que quizá la señal no era buena, pero descarté rápidamente esa posibilidad al ver que el cliente de iOS encontraba absolutamente todos los canales a la primera. Por tanto, es un problema del cliente de escritorio. Debe ser que el cliente de iOS es más permisivo a la hora de detectar canales o algo así, pero el caso es que funciona bien, y a la primera.

Durante unos días fui tirando con el cliente de iOS y con los canales que el cliente de escritorio pudo encontrar, hasta que me dispuse a comprobar si podía extraer los ficheros de datos de los canales de la aplicación de iOS y ponerlos en el directorio de configuración del cliente de escritorio. Lo primero que probé fue a mirar si en iTunes la aplicación permitía el acceso a los ficheros compartidos, pero no era el caso. Así que pensé que la mejor opción podía ser hacer un backup y comprobar si contenía los ficheros de datos de la app.

El primer paso fue exitoso: hice un backup de mi iPad en iTunes y luego miré si contenía información de la app, y así era. El problema es que los nombres de los ficheros guardados en el backup son huellas SHA-1. Hay que mirar en algún sitio dónde se relacionan esas huellas con los nombres originales de los ficheros, y ese sitio es el fichero Manifest.mbdb. Ese fichero tiene un formato propietario, pero hay gente que lo ha logrado interpretar. Utilizando este script pude sacar un listado de ficheros y filtrar sólo los que me interesaban. Al ver que los ficheros de datos se llamaban de forma muy parecida a los del cliente de escritorio me figuré que podría ser factible copiar esos ficheros al directorio de configuración del cliente de escritorio y ver si éste era capaz de usarlos tal cual, así que eso hice.

Hago un respaldo de los ficheros que tenía el programa, copio los ficheros del cliente de iOS, les pongo el mismo nombre que los que había antes, arranco el programa preguntándome si funcionará o cascará fuertote, y al final…

¡Victoria!

Por tanto, me he guardado una copia de esos ficheros por si la necesito más adelante. Ya he alcanzado mi propósito, así que puedo considerar este tema como zanjado.

Siguiente Entrada Entrada Anterior