Implementación de un túnel ICMP en el kernel de Linux: Encapsulando TCP/UDP en solicitudes Echo
Un túnel ICMP a nivel del kernel de Linux permite encapsular tráfico TCP/UDP dentro de paquetes ICMP Echo Request, eludiendo filtros de red estándar. Este enfoque es útil para investigar la pila de red, probar la intercepción de paquetes y comprender cómo funciona Netfilter. El artículo desglosa la arquitectura del módulo del kernel que implementa la traducción de tráfico a través de los hooks NF_INET_POST_ROUTING y NF_INET_LOCAL_IN utilizando tasklets para el envío asíncrono.
Arquitectura del túnel ICMP en el kernel de Linux
El módulo consta de tres componentes clave: dos hooks de Netfilter y un tasklet para el envío de paquetes. El hook NF_INET_POST_ROUTING intercepta los paquetes TCP/UDP salientes antes de que se envíen a la red, los convierte en solicitudes ICMP echo y pasa el control al tasklet. El segundo hook —NF_INET_LOCAL_IN— captura los paquetes ICMP entrantes, extrae el tráfico original y lo enruta hacia la interfaz loopback para su entrega a las aplicaciones. El tasklet maneja el envío diferido de paquetes mediante dev_queue_xmit, minimizando el bloqueo en el contexto de interrupción.
El registro de hooks utiliza la prioridad NF_IP_PRI_FIRST para garantizar un procesamiento en primer orden. Esto es crítico, ya que la interferencia de otros módulos previos podría alterar la integridad de la encapsulación o desencapsulación. La gestión de memoria se basa en sk_buff —la estructura central de la pila de red de Linux—, que requiere una reserva cuidadosa de cabeceras y una liberación adecuada mediante kfree_skb en caso de errores.
Desglose detallado de output_hook y create_packet_output
La función output_hook se llama para cada paquete saliente. Delega la creación del envoltorio ICMP a la función create_packet_output, que:
- Verifica si el protocolo es TCP o UDP —si no lo es, devuelve NULL y el paquete continúa su ruta sin cambios.
- Obtiene la dirección MAC del destinatario mediante
__ipv4_neigh_lookup, que es necesaria para formar la cabecera Ethernet. - Lineariza el
sk_buffconskb_linearize, ya que las operaciones posteriores de copia de datos requieren un búfer contiguo. - Determina el tipo de protocolo de transporte (0 para UDP, 1 para TCP), la longitud de la cabecera y el tamaño de la carga útil.
- Asigna un nuevo
sk_buffconsiderando el espacio reservado bajo las cabeceras (LL_RESERVED_SPACE) y los datos de cola necesarios (needed_tailroom). - Construye secuencialmente las cabeceras: Ethernet, IPv4, ICMP, copiando la cabecera de transporte y los datos en el cuerpo ICMP.
- Calcula las sumas de verificación para IP e ICMP utilizando
ip_fast_csumeip_compute_csum. - Devuelve el paquete listo para enviar.
Un detalle clave es el uso del campo icmp->un.echo.id para pasar información de servicio sobre el tipo de protocolo original e identificador de flujo. Esto permite al lado receptor reconstruir correctamente el paquete original sin metadatos adicionales fuera de la estructura ICMP.
Manejo de paquetes entrantes y enrutamiento loopback
En el lado receptor, la función input_hook analiza cada paquete ICMP entrante. Si coincide con el formato del túnel (Echo Request con un patrón conocido en el campo ID), el módulo:
- Extrae la cabecera de transporte y los datos del cuerpo ICMP.
- Crea un nuevo
sk_buffque simula un paquete TCP/UDP entrante. - Establece el dispositivo de destino como la interfaz loopback (
dev_set_name(skb, "lo")). - Cambia las direcciones MAC a localhost y llama a
netif_rx_ni()para inyectar el paquete en la pila de red.
Esto hace que el kernel procese el paquete como si viniera de fuera, pero a través de la interfaz lo. Las aplicaciones reciben los datos sin cambios, sin ser conscientes de la encapsulación. Importante: no se usa NF_STOLEN aquí —el paquete no se "roba" sino que se reemplaza, por lo que se devuelve NF_ACCEPT tras una inyección exitosa.
Detalles técnicos críticos y limitaciones
La implementación enfrenta varias limitaciones técnicas:
- Fragmentación: Los paquetes ICMP pueden fragmentarse en ruta, pero la implementación actual no maneja fragmentos —asumiendo un MTU suficiente para la encapsulación completa.
- Seguridad: La falta de cifrado o autenticación hace que el túnel sea vulnerable a suplantaciones y ataques de hombre en el medio.
- Rendimiento: Cada paquete requiere asignar un nuevo
sk_buff, copiar datos y calcular sumas de verificación —lo que genera sobrecarga de CPU. - Solo IPv4: El módulo no soporta IPv6, ya que utiliza
ip_hdry__ipv4_neigh_lookup. - Dependencia de MAC: Requiere una entrada ARP para la IP destino; de lo contrario, el paquete se descarta.
A pesar de estas limitaciones, el proyecto es excelente para aprender: cubre operaciones de Netfilter, gestión de memoria del kernel, construcción de cabeceras de red e interacciones en tiempo real de las capas OSI.
Lecciones clave
- El túnel ICMP encapsula TCP/UDP en solicitudes Echo, permitiendo eludir algunos filtros de red.
- Se utilizan hooks de Netfilter con prioridad máxima para interceptar tráfico antes/después del enrutamiento.
- Los tasklets permiten el envío asíncrono sin bloquear el contexto de interrupción.
- En el lado receptor, los paquetes se inyectan en loopback para una entrega fluida a las aplicaciones.
- La implementación es educativa —no está destinada a producción debido a la falta de seguridad y manejo de fragmentos.
— Editorial Team
Aún no hay comentarios.