Retour à l'accueil

Tunnel ICMP dans le noyau Linux : encapsulation TCP/UDP

L'article détaille l'implémentation d'un tunnel ICMP dans le noyau Linux qui encapsule le trafic TCP/UDP dans des requêtes d'écho ICMP. Couvre les hooks Netfilter, le travail avec sk_buff, les tasklets et l'injection de paquets dans loopback.

Plongée dans le noyau : comment TCP/UDP se cache dans les échos ICMP
Advertisement 728x90

## Implémentation d'un tunnel ICMP dans le noyau Linux : Encapsulation de TCP/UDP dans des requêtes Echo

Un tunnel ICMP au niveau du noyau Linux permet d'encapsuler le trafic TCP/UDP à l'intérieur de paquets ICMP Echo Request, contournant les filtres réseau standards. Cette approche est utile pour étudier la pile réseau, tester l'interception de paquets et comprendre le fonctionnement de Netfilter. L'article décompose l'architecture du module noyau qui implémente la traduction de trafic via les crochets NF_INET_POST_ROUTING et NF_INET_LOCAL_IN en utilisant des tasklets pour l'envoi asynchrone.

Architecture du tunnel ICMP dans le noyau Linux

Le module se compose de trois composants principaux : deux crochets Netfilter et un tasklet pour l'envoi de paquets. Le crochet NF_INET_POST_ROUTING intercepte les paquets TCP/UDP sortants avant leur envoi vers le réseau, les convertit en requêtes ICMP echo et passe le contrôle au tasklet. Le second crochet — NF_INET_LOCAL_IN — capture les paquets ICMP entrants, extrait le trafic original et le route vers l'interface loopback pour livraison aux applications. Le tasklet gère l'envoi différé des paquets via dev_queue_xmit, minimisant le blocage dans le contexte d'interruption.

L'enregistrement des crochets utilise la priorité NF_IP_PRI_FIRST pour garantir un traitement en premier. Cela est critique, car une interférence d'autres modules au préalable pourrait perturber l'intégrité de l'encapsulation ou de la décapsulation. La gestion de la mémoire repose sur sk_buff — la structure centrale de la pile réseau Linux — qui nécessite une réservation minutieuse des en-têtes et une libération appropriée via kfree_skb en cas d'erreur.

Google AdInline article slot

Décomposition détaillée de output_hook et create_packet_output

La fonction output_hook est appelée pour chaque paquet sortant. Elle délègue la création de l'enveloppe ICMP à la fonction create_packet_output, qui :

  • Vérifie si le protocole est TCP ou UDP — sinon, retourne NULL et le paquet poursuit sa route inchangé.
  • Récupère l'adresse MAC du destinataire via __ipv4_neigh_lookup, nécessaire pour former l'en-tête Ethernet.
  • Linéarise le sk_buff avec skb_linearize, car les opérations de copie de données suivantes requièrent un tampon contigu.
  • Détermine le type de protocole de transport (0 pour UDP, 1 pour TCP), la longueur de l'en-tête et la taille de la charge utile.
  • Alloue un nouveau sk_buff en tenant compte de l'espace réservé sous les en-têtes (LL_RESERVED_SPACE) et des données de queue (needed_tailroom).
  • Construit séquentiellement les en-têtes : Ethernet, IPv4, ICMP, en copiant l'en-tête de transport et les données dans le corps ICMP.
  • Calcule les sommes de contrôle pour IP et ICMP en utilisant ip_fast_csum et ip_compute_csum.
  • Retourne le paquet prêt à être envoyé.

Un détail clé est l'utilisation du champ icmp->un.echo.id pour transmettre des informations de service sur le type de protocole original et l'identifiant de flux. Cela permet au côté récepteur de reconstruire correctement le paquet original sans métadonnées supplémentaires en dehors de la structure ICMP.

Gestion des paquets entrants et routage loopback

Côté récepteur, la fonction input_hook analyse chaque paquet ICMP entrant. S'il correspond au format du tunnel (Echo Request avec un motif connu dans le champ ID), le module :

Google AdInline article slot
  • Extrait l'en-tête de transport et les données du corps ICMP.
  • Crée un nouveau sk_buff imitant un paquet TCP/UDP entrant.
  • Définit le périphérique de destination comme l'interface loopback (dev_set_name(skb, "lo")).
  • Modifie les adresses MAC en localhost et appelle netif_rx_ni() pour injecter le paquet dans la pile réseau.

Cela fait en sorte que le noyau traite le paquet comme s'il provenait de l'extérieur, mais via l'interface lo. Les applications reçoivent les données inchangées, sans connaissance de l'encapsulation. Important : NF_STOLEN n'est pas utilisé ici — le paquet n'est pas "volé" mais remplacé, donc NF_ACCEPT est retourné après injection réussie.

Détails techniques critiques et limitations

L'implémentation fait face à plusieurs limitations techniques :

  • Fragmentation : Les paquets ICMP peuvent se fragmenter en route, mais l'implémentation actuelle ne gère pas les fragments — en supposant un MTU suffisant pour une encapsulation complète.
  • Sécurité : Absence de chiffrement ou d'authentification rend le tunnel vulnérable aux attaques de spoofing et MITM.
  • Performance : Chaque paquet nécessite l'allocation d'un nouveau sk_buff, la copie de données et le calcul de sommes de contrôle — cela crée une surcharge CPU.
  • IPv4 uniquement : Le module ne supporte pas IPv6, car il utilise ip_hdr et __ipv4_neigh_lookup.
  • Dépendance MAC : Nécessite une entrée ARP pour l'IP cible ; sinon, le paquet est abandonné.

Malgré ces limitations, le projet est excellent pour l'apprentissage : il couvre les opérations Netfilter, la gestion de mémoire du noyau, la construction d'en-têtes réseau et les interactions en temps réel des couches OSI.

Google AdInline article slot

Points clés à retenir

  • Le tunnel ICMP encapsule TCP/UDP dans des requêtes Echo, lui permettant de contourner certains filtres réseau.
  • Des crochets Netfilter avec priorité maximale sont utilisés pour intercepter le trafic avant/après routage.
  • Les tasklets permettent un envoi asynchrone sans bloquer le contexte d'interruption.
  • Côté récepteur, les paquets sont injectés dans loopback pour une livraison transparente aux applications.
  • L'implémentation est éducative — non destinée à la production en raison de l'absence de sécurité et de gestion des fragments.

— Editorial Team

Advertisement 728x90

Lire ensuite