TwIP: Un stack IP cuyo código cabe en un twit

Hubo una vez un maestro programador que escribía programas no estructurados. Un programador novicio, buscando imitarlo, también comenzó a escribir programas no estructurados. Cuando el novicio le pidió al maestro evaluar su progreso, el maestro lo criticó por escribir programas no estructurados, diciendo: “Lo que es apropiado para el maestro no es apropiado para el novicio. Debes entender el Tao antes de trascender la estructura.” El Tao de la Programación

INTRODUCCIÓN

 

Tengo la intención de comenzar una serie de artículos relacionados con la conectividad de sistemas embebidos a redes LAN y, dentro de este propósito, me ha parecido interesante comenzar escrbiendo sobre TwIP. TwIP es el stack IP que menos caracteres de código requiere, de hecho, su código fuente completo cabe en un twit. Evidentemente, como el lector podrá suponer, no se trata de una pila IP profesional lista para incluir y usar en nuestros diseños, sino que tiene una finalidad igualmente noble: divertirse programando.

Hace ya algunos años, cuando me pasé de programar en GW-BASIC a C, me entretenía tratando de hacer el código en el menor número de lineas posible y, dentro de estas lineas, tratando que fuesen del tamaño más pequeño posible. Con C las posibilidades en este campo son muy interesantes.  TwIP es una de estas posibilidades que, además, nos servirá como apoyo para exponer el mecanismo de comunicación ICMP. De hecho, la única funcionalidad que ofrece TwIP es responder a un ping.

TwIP fue escrito por Adam Dunkels, quien se aficionó a este juego de escribir programas en C super-reducidos tras observar cómo Razvan Musaloiu escrbía un twit con código para reventar un Mac OSX 10.5.8 y de este modo nació este stack IP.

EL CÓDIGO

 

El código de TwIP es el siguiente:

short s[70];*l=s;t;main(){for(;;){read(0,s,140);if((s[4]&65280)==256&s[10]==8){s[10]=0;s[11]+=8;t=l[4];l[4]=l[3];l[3]=t;write(1,s,140);}}}

Si bien el código desglosado y comentado puede verse en [1], a continuación comento con mis propias palabras el mismo, con la finalidad también de introducir el protocolo ICMP:

Explicación del código: variables de programa

short s[70];
*l=s;
t;

Como puede verse, se declara un buffer “s” que servirá para las tramas de recepción y de transmisión. Si se ha elegido hacerlo de 16 bits es porque el protocolo ICMP, como se verá más adelante, incluye un checksum de 16 bits y ocupará menos caracteres el código necesario para operar con él. Una de las viejas herencias de C es que cuando no se especifican tipos de datos, éstos se suponen por defecto como int, este es el motivo por el que, para ahorrar caracteres, el puntero al buffer y la variable “t” se han declarado de esta singular manera. Por supuesto, esto producirá un warning al compilar, pero nada impedirá que nuestro twit se ejecute correctamente.

Del mismo modo, se declara main() en lugar del típico void/int main (void) con mótivo de ahorrar caracteres para cumplir el peculiar requisito de que el código pueda caber en un solo twit.

Explicación del código: recepción de datos

Así pues el código continua con la declaración del main, dentro del cual se ejecuta un bucle sin fin:

main()
{   //Inicio del cuerpo del programa
      for(;;) {  //Inicio del bucle sin fin

Llegados a este punto, necesitaremos recibir la información y almacenarla en el buffer s, lo cual se hace mediante la función read. Es importante destacar en este punto, que se lee sobre el descriptor de fichero 0, para lo cual, deberemos haber redirigido la entrada del puerto IP al descriptor STDIN_FILENO. En caso contrario, aquí habría que indicar en lugar de 0 el descriptor correspondiente a dicha entrada. De este modo, el  código continua como sigue:

      read(0,s,140);

Explicación del código: comprobando la trama recibida

En este momento, como se verá cuando se resuma en detalle el protocolo ICMP, se debería de realizar una serie de comprobaciones:

  1. Se debería comprobar la longitud del paquete para verificar que al menos es del tamaño de una cabecera IP
  2. Se debería comprobar que la cabecera es válida de acuerdo al formato IPv4
  3. Se debería comprobar qué tipo de paquete es, y si es de tipo ICMP:
  • Se debería comprobar qué tipo de ICMP es, por ejemplo, si es de tipo ECHO, se trata de un comando ping que requiere respuesta.

Sin embargo, debido al singular y minimalista requisito de poder introducir todo el código en un twit, no se dispone, al menos en esta versión, de espacio más que para realizar estas últimas comprobaciones, esto es, TwIP comprueba únicamente si es un paquete ICMP y, en caso de que así sea, comprueba si es un mensaje de tipo ECHO (ping), en cuyo caso envía la respuesta.

Veamos primero el código de comprobación:

      if( ( s[4] & 65280 ) == 256 \ //Si el byte más significativo de s[4] vale 0xFF (protocolo ICMP)
         & s[10] == 8 ) {           //Y además s[10] vale 8 (ECHO) 

LA CABECERA IPv4

 

Dentro de la cabecera IPv4, el protocolo se indica en el byte 9 de dicha cabecera, por tanto, tratándose de un array de elementos de 16 bits, habrá que ir a realizar la comprobación en el elemento 4, y dentro de él, encontraremos el campo protocolo en el byte más significativo, salvo que trabajemos con un protocolo big-endian, en cuyo caso el protocolo se encontrará en el byte menos significativo y habría que realizar el and con 255 en lugar de con 65280. Aquí se ha supuesto que se trabaja en formato little-endian.

Esta comprobación puede verse claramente si se observa la cabecera IPv4:

“]”]Cabecera IPv4

Imagen de la cabecera IPv4. Imagen obtenida de [2

Como puede verse en la imagen anterior, la información, en función del protocolo, comenzará a enviarse a partir del byte 20, en este caso, al tratarse del protocolo ICMP, en el byte 20 se tendrá una estructura de datos de acuerdo a dicho protocolo, y en él, el primer byte es es el que indica el tipo de operación, y ECHO es la operación con identificador 8. De nuevo, al tratarse de un array de elementos de 16 bits, se compara el elemento 10, y suponiendo una máquina little-endian, se espera que el dato esté en el byte menos significativo. Esto se ilustra gráficamente en la siguiente figura, donde se muestra la estructura de datos del protocolo ICMP.

“]Protocolo ICMP

Protocolo ICMP: estructura de datos. Imagen obtenida de [2

Una vez explicadas las comprobaciones que realiza el código de TwIP, se continúa con la explicación del código.

Explicación del código: preparando el paquete que será enviado

La contestación al ping es una trama prácticamente idéntica, con tres consideraciones:

  1. IP de origen e IP de destino han de cambiar su posición en la cabecera IPv4
  2. El tipo de comando ICMP será ECHO_REPLY en lugar de ECHO
  3. Se deberá recalcular el Checksum de la trama ICMP

El código TwIP hace esto con las siguientes instrucciones:

             s[10] = 0; //ECHO_REPLY está definido como 0
             s[11] += 8; // Se actualiza el checksum (little-endian)
   /* Se intercambian los valores de IP origen y destino */
             t = l[4];
             l[4] = l[3];
             l[3] = t;

TIPOS DE MENSAJES EN EL PROTOCOLO ICMP

 

Ya hemos aprovechado este pequeño código para ilustrar el funcionamiento de las cabeceras IPv4, así como para comentar el funcionamiento de uno de sus protocolos, el ICMP. Dentro de este protocolo hemos podido ver 2 mensajes ECHO y ECHO_REPLY que sirven para enviar un ping y para responderlo, respectivamente.

Llegados a este punto, y aunque nuestra pequeña pila IP no soporta estos comandos, parece interesante comentar el resto de mensajes ICMP que pueden enviarse, de modo que el lector interesado, con muy poco trabajo por su parte, podrá fácilmente desarrollar un stack IP que tenga todas las funcionalidades del protocolo ICMP.

Los comandosICMP, junto a su valor numérico, pueden verse en la siguiente tabla:

Etiqueta y valor del comando Descripción del comando
#define ECHO_REPLY                            0 Respuesta de eco
#define DESTINATION_UNREACHEABLE  3 Destino inaccesible
#define SOURCE_QUENCH                     4 Disminución del tráfico desde el origen
#define REDIRECT                                5 Redireccionar – cambio de ruta
#define ECHO                                      8 Solicitud de eco
#define TIME_EXCEEDED                      11 Tiempo excedido para un datagrama
#define PARAMETER_PROBLEM              12 Problema de parámetros
#define TIMESTAMP                              13 Solicitud de marca de tiempo
#define TIMESTAMP_REPLY                    14 Respuesta de marca de tiempo
#define INFORMATION_REQUEST           15 Solicitud de información – obsoleto-
#define INFORMATION_REPLY                16  Respuesta de información – obsoleto-
#define ADDRESS_MASK                        17 Solicitud de máscara de dirección
#define ADDRESS_ASK_REPLY                18 Respuesta de máscara de dirección

 Explicación del código: Realizando el envío

Si el lector ha llegado hasta aquí, no encontrará necesario que continúen explicándole el código, de modo que únicamente incluiré el final del twit:

[ ... ] write(1,s,140);}}}

 

¿TE GUSTÓ EL ARTÍCULO?

 

¿Te parece interesante que exista un blog de referencia en español sobre electrónica y sistemas embebidos? Ayuda a que Arte en 8 bits crezca, para ello sólo tienes que pulsar en los botones para compartirlo en redes sociales, Twitter o Google+. De este modo contribuirás a que Arte en 8 bits se posicione mejor, y por tanto podremos crecer e ir ofreciéndote cada vez un mejor contenido y de mayor calidad.

De antemano, muchas gracias.

 

BIBLIOGRAFÍA

 

[1] TwIP: A Tweet-sized IP-stack (well, not really)

[2] Protocolos de Comunicación. Networking and Emerging Optimization. Universidad de Málaga.

4 Comentarios a "TwIP: Un stack IP cuyo código cabe en un twit"

  1. newbie's Gravatar newbie
    16 noviembre, 2011 - 8:28 | Enlace permanente

    Hola,
    me ha parecido muy interesante. He compilado el código, obteniendo los warnings de los que hablabas, pero ahora no sé como probarlo.
    ¿Me puedes decir cómo?

Deja una respuesta

eighteen − 13 =