Reading time: < 1 minute
Hablando sobre el problema del articulo sobre el desafio de networking. También aprovecho para enlazar una buena referencia sobre como comprender los problemas de secuencias TCP:
Espero haberme explicado bien y haber podido describir el problema algo mejor que en el articulo anterior, ya que no es sencillo describir un problema tan inusual.
Se dispone de un dispositivo de hardware con un linux embedded al que no se puede acceder ya que el fabricante no lo facilita, se ha intentado acceder pero no hemos sido capaces de acceder ni con nuestros medios ni con los de una importante empresa de electrónica. Creemos que el kernel es un 2.4.X por lo que observamos. El dispositivo tiene una pantalla y su finlidad es mediante un protocolo propietario y un protocolo de transporte de ficheros (FTP) descargar una playlist para reproducir en la pantalla.
A través de red se conecta al servidor del fabricante de donde recoje una playlist y unos contenidos multimedia. Escencialmente usa los puertos:
TCP/8889 (protocolo de control del fabricante) va en ‘plain text’ ya le hemos hecho la ingenieria inversa.
FTP en modo pasivo
Con el servidor del fabricante descarga el 99% de la veces correctamente y sin problemas. En el fichero adjunto ‘korea-ok.cap’ si lo examinais podreis ver que todo se desarrolla perfectamente. La IP privada que podeis ver es del dispositivo en la LAN y a través de una LMDS se conecta a Korea a la IP: 210.114.220.180, si os fijais el fabricante usa como servidor FTP un ‘Serv-U’ para Windows.
Problema
Se ha implementado el protocolo propietario del fabricante con Python y funciona perfectamente, el problema es al hacer la descarga por FTP. El dispositivo se conecta a nuestro servidor FTP y de forma completamente aleatoria cierra la transmisión sin motivo aparente y se reinicia el dispositivo. Esto siempre pasa mientras se esta haciendo una conexión FTP-control (21/tcp) o FTP-data (puerto aleatorio del ftp pasivo/tcp).
En el fichero ‘cwd-fail.cap’ se puede ver uno de los típicos fallos que tiene el dispositivo al intentar descargar a un servidor FTP local (en este caso un proftpd en una Gentoo). Concrectamente al mandar el comando FTP ‘CWD’ el dispositivo decide cerrar la conexión y no seguir con la descarga. Después de varios intentos se reinicia. Para no perderos con los paquetes he dejado en la captura sólo el socket que tiene el problema.
Para no despistar recordar que esto no tiene porqué pasar en el canal de FTP-control puede pasar también en un FTP-data, puede pasar al 1% de descarga del fichero, al 30%, 50%, 98%… es completamente aleatorio.
Para tener más ejemplos de errores se adjunta el fichero ‘local-fail.cap’ donde se puede ver como se da un error igual al anterior pero ahora en el canal de datos de FTP. Concretamente podeis ver como se cierra el socket en el paquete 916 sin motivo apararente. Comentar que los errores de checksum de TCP no son relevantes ya que son debidos a que la tarjeta de red no estaba como sigue:
En otras pruebas se han hecho con los parametros comentados y el error es el mismo. A pesar de que ya no aparecen las alertas por ‘checksum error’. Si se cree vital tener una captura sin los errores de checksum no hay problema en hacerla. Pero después de meses de pruebas esta claro que esto no es relevante.
Para demostrar que el comportamiento es aleatorio a continuación se adjunta un fichero ‘local-ok.cap’ con la captura de una sesión en el serividor FTP local que ha funcionado perfectamente. Se puede observar en el paquete: 18975 que se descarga bien el contenido de un fichero, concretamente un fichero .mpg, con este fichero finaliza todo el traspaso de datos correctamente.
Hardware y soft probado
Se han hecho infinidad de pruebas y de combinaciones:
5 servidores distintos:
1 debian con kernel 2.6.24.5-grsec-xxxx-grs-ipv4-64 en el proveedor ovh.es (100Mpbs simétricos sin restricciones), servidor FTP proftpd puerto 2090/tcp
1 debian con kernel 2.6.18-5-686 proveedor jazztel sin fw, ni restricción de ningún tipo 100Mbps simétricos contra internet y servidores FTP en el puerto 21 pure-ftpd y en el puerto 2090 proftpd.
1 ubuntu con kernel 2.6.24-16-server proveedor jazztel con fortinet como fw en modo transparente, proftpd en puerto 2090.
1 gentoo con kernel 2.6.25-gentoo-r5 en red local con proftpd en puerto 2090.
1 windows xp virtualizado con vmware workstation 6 sobre gentoo con un servidor FTP Serv-U, la tarjeta de red virtual en modo bridget con la del sistema operativo host.
el comportamiento es el mismo con todas la combinaciones
Intuición de solución
Jugando con los parámetros del kernel de TCP (/proc/sys/net/ipv4) se consiguen hacer cambios de comportamiento en el error. Por ejemplo, se han hecho pruebas con:
También se han hecho pruebas limitando el ancho de banda, y con algunos otros parámetros de kernel que ahora no recuerdo. Se ha probado de opimitzar los servers para rendir al máximo, al mínimo, por defecto… etc.
Lo que se consigue con todo esto es conseguir que algunas veces se haga la descarga, pero no se consigue afianzar patrones de forma feaciente, es decir, a menudo se sigue cerrando la conexión TCP.
FAQ de obviedades
Es obvio que el firmware del dispositivo esta mal hecho, pero esto no se puede tocar.
El dispositivo se puede configurar via una compact flash, donde se guarda un fichero de configuración, un fichero binario compilado para ARM y el contenido multimedia que se va descargando.
Se ha intentado hablar mil veces con el fabricante pero es como hablar con una pared, a parte los técnicos no hablan inglés, sólo coreano. Increible, no?
El problema lo tiene el stack TCP del dispositivo o algún otro elemento similar. Este es el que cierra la conexión!!! no se puede mantener la conexión abierta des del servidor cuando el dispositivo la ha cerrado, lo único que se puede hacer es evitar que el cliente la cierre. El problema es como.
Si! el server del fabricante descarga bien via FTP en el 99% de los casos. Este es el gran probleam, parece tonta la pregunta pero me la han hecho como 20 veces, así que merecia estar aquí.
Ficheros
Los ficheros de los que se habla en este correo de pueden descargar de:
http://oriolrius.cat/downloads/korea-ok.cap
http://oriolrius.cat/downloads/cwd-fail.cap
http://oriolrius.cat/downloads/local-fail.cap
http://oriolrius.cat/downloads/local-ok.cap
Desafio
El entorno de laboratorio lo tengo montado en la oficina, esta abierta 24×7 para quedar conmigo para hacer pruebas in-situ. Obviamente responderé todo lo que sea online y orientaré con lo que pueda y más.
Este problema lo arrastro desde hace unos 4 meses y llevo casi 4 dias sin vida, sólo obsesionado buscando la solución pero no hay manera de ver la luz.
No dispongo de muchos recursos, debido a que ya he perdido muchísmo dinero buscando la solución durante todo este tiempo, pero bajo resultados se recompensará tanto como sea posible a la mente privilegiada que consiga dar con la solución.
Ya tengo solución
Después de darle vueltas al tema de momento no contaré las varias soluciones que a dia de hoy ya he enontrado al problemón. Así pue aprovecharé el problema para lanzar el podcast 1×11 describiendo con todo detalle el problema y dando algunas pistas de como llegar a la solución. Quizá a nadie le pique tanto la curiosidad como para seguir la solución con este detalle pero de esta forma mantengo un poco la intriga y si alguien realmente necesita saber la solución sin seguir el culebrón sólo tiene que mandarme un correo privado y se lo contaré. Para hacer boca deciros que la intuición de solución que tenia no era mala.
L’abril del 2007 ja vaig parlar sobre tcpxd el qual permetia fer el mateix que rinetd. Obviament tenen algunes diferencies funcionals, sota el meu punt de vista rinetd és més professional ja que integra a partir d’un fitxer de coniguració la possibilitat de redireccionar un port TCP en qualsevol de les IPs que estem publicant en el host on es llenci el servei. A més el fitxer de configuració ja diu tot el que cal saber de com funiona:
Algunes altres funconalitats que m’han agradat molt és la possibilitat de fer una llista ACL de rangs d’IPs permesos i no permesos. Per si això fos poc suporta logging. A més el podem trobar com a paquet de les distribucions de linux: gentoo, ubuntu i debian. Potser hi ha altres distribucions que el tenen però la veritat és que no les uso. També aprofitor per recordar-vos que si necessiteu fer coses d’aquest estil amb windows podeu llegir aquest article: Redirigir ports amb Windows (Port Forwarding, DNAT, NAPT).
Si esteu familiaritzats amb iptables i voleu fer una redirecció poseu-hi una mica d’enginy i podreu fer-ho amb relges tan simples com aquesta:
Fins ara per poder seguir un protocol dins del enllaç TCP, o sigui els missatges de la capa 5, sempre acabava capturant-lo amb el wireshark o en el seu defecte amb el tcpdump generava un fitxer .cap que després obria al wireshark i a través d’una funció tan simple com el Follow TCP stream em montava la sessió de capa d’aplciació que podia seguir de forma ben còmode. El gran descobriment que vaig fer l’altre dia és el tcpflow una eina la mar de simple i lleugera que com no podia ser d’altre forma usa les llibreries libpcap, le mateixes que el tcpdump i el wireshark per mostrar-nos de forma completament visual i simple a través de la consola o contra un fitxer el contingut de la sessió TCP. Espero que li tregueu tan profit com jo a l’eina.
Encara m’enrecordo fa quasi 10 anys que per entrar a l’IRC usabem aplicatius d’aquest tipus per tal d’spoofejar la nostre IP. Doncs bé, avui he hagut de montar un procés que fa el mateix que usaben en aquelles èpoques però aquest cop per temes més seriosos. Així doncs, perquè si a algú li cal una eina que re-envii una connexió TCP d’un servidor a un altre de forma estàtica simple senzilla i ben fet he trobat el tcpxd. Ell mateix permet llençar-se com a dimoni, suporta múltiples connexions simultanees de forma asíncrona, de fet les típiques funcions xorres de tota la vida i amb una sintaxis ben senzilla:
tcpxd780210.0.0.17802
Són d’aquelles eines xorres que t’ajuden a sortir de més d’un embolic quan la potència del NAT del firewall, router o el que sigui que tinguem pel mig no ens permet fer el que volem.
Aquesta eina la vaig veure fa molt temps al blog de Xavier Caballé, però no me l’havia pogut mirar fins avui i per no perdre la referència aquí va aquesta nota. Jo diria que la funcionalitat queda molt clara en el títol de l’article i en el propi nom de l’eina. Amb cutter quan veiem un socket TCP actiu al nostre linux, o tots els sockets que provenen d’una IP, els podrem desconnectar a l’instant de forma ben simple.
Tenia un problema amb un servidor de correu SMTP al qual no podia accedir des del servidor de correu de la feina. Encanvi des d’altres IPs del nostre mateix rang si que tenia accés al port 25/tcp d’aquest servidor remot. Doncs resulta que el servidor en qüestió té instal·lat un InterScan Messaging Security Suite de la casa TrendMicro i al servidor de correu de l’empresa jo hi tenia activat el ECN (Explicit Congestion Notification). El problema esta en que quan s’envia un “SYN” en el handshake TCP entre els nostres servidors el paquet TCP té activats dos flags més a part del ‘SYN’, el ‘W’ i el ‘E’.
Aquí podeu veure el que envia el meu servidor amb ECN, flags SWE:
14:12:31.257939 IP 1.1.1.1.44435 > 2.2.2.2.25: SWE 2986809236:2986809236(0) win 5840 <mss 1460,sackOK,timestamp 338497211 0,nop,wscale 0>
El que envia un altre servidor que no té ECN, flag S:
14:13:02.225358 IP 1.1.1.2.37876 > 2.2.2.2.25: S 3871099907:3871099907(0) win 5840 <mss 1460,sackOK,timestamp 3419720577 0,nop,wscale 2>
Per comprovar si realment tenim el ECN activat al kernel:
# cat /proc/sys/net/ipv4/tcp_ecn
Per desactivar el ECN del nostre kernel:
echo 0 > /proc/sys/net/ipv4/tcp_ecn
Només fent això la cosa ja ha començat a funcionar perfectament. Així doncs, dubto que mai a algú li passi algo tan enravassat com el que m’acaba de pasar però aquí queda explicat.