Programmation d'applications bis
From Livre IPv6
Contents
HISTORIQUE DU TRAVAIL SUR CE CHAPITRE
- 2009-06-30: Copié-Collé séquentiel de l'ancienne Version sur cette page (Etienne)
Résumé (TEXTE REPRIS DE L'ANCIENNE VERSION)
L'évolution de IPv4 vers IPv6 a été conçue pour minimiser les changements visibles. Un grand nombre de concepts n'ont pas changé : les noms, les "ports", l'envoi et la réception de données,... Un certain nombre de points ont malgré tout dû être modifiés. Le principal est lié à la taille de l'adresse : en IPv4, une adresse a une longueur de 32 bits (et de nombreux programmes confondent les types adresse et entier) alors qu'en IPv6 une adresse a une longueur de 128 bits ; les types liés aux adresses doivent donc être modifiés. En fait l'effet est plus profond : les nouvelles structures sont plus grandes, et certaines réservations de mémoire avec conversion de type implicite (en particulier : un entier pour une adresse, une struct sockaddr pour une struct sockaddr_in, un tampon de 16 octets pour afficher une adresse sous forme numérique) doivent être corrigés sous peine de débordement de mémoire.
L'interface de programmation réseau ("API") la plus connue est l'interface "socket" (dite aussi interface "BSD"). Le but de ce chapitre est de présenter pour cette interface de programmation les modifications introduites pour supporter IPv6, et notamment de donner une brève description des nouvelles primitives d'appel au DNS et de conversion d'adresses.
Ces modifications ont été définies pour être aussi transparentes que possible, et, s'il est en pratique toujours nécessaire de modifier un programme pour le porter de IPv4 à IPv6, un programme conçu avec des règles de typage strict est portable sans grandes modifications.
Ce chapitre illustrera l'interface de programmation "socket" pour IPv6 en présentant plusieurs exemples de programmes. Plus précisément, il détaillera successivement :
- un programme combinant les différentes fonctions de conversion d'adresse ;
- un client/serveur TCP calculant le nombre d'utilisateurs connectés sur une machine cible. En particulier, on aura soin de comparer les codes IPv4 et IPv6 de ce client/serveur, ce qui amènera à constater qu'à ce niveau de programmation, la migration vers IPv6 n'offre aucune difficulté ;
- un "mini ping" qui permettra de se familiariser avec le protocole ICMPv6 qui présente de notables différences avec son prédécesseur le protocole ICMPv4 ;
- un exemple qui génère un trafic multicast, avec abonnement et désabonnement ;
- un programme illustant l'utilisation de l'API socket avancée.
L'interface de programmation "socket" IPv6 (TEXTE REPRIS DE L'ANCIENNE VERSION)
Ce qui a changé
Les structures de données d'adresses
Une nouvelle famille d'adresses ayant pour nom AF_INET6 et dont la valeur peut varier d'une implémentation à l'autre, a été définie (dans sys/socket.h). Également, une nouvelle famille de protocoles ayant pour nom PF_INET6 a été définie (dans sys/socket.h). En principe, on doit avoir :
#define PF_INET6 AF_INET6
La structure de données destinée à contenir une adresse IPv6 est définie comme suit (dans netinet/in.h) :
struct in6_addr { uint8_t s6_addr[16]; };
les octets constituant l'adresse étant rangés comme d'habitude dans l'ordre réseau (network byte order).
La structure de données IPv6 struct sockaddr_in6, est équivalente à la structure struct sockaddr_in d'IPv4. Elle est définie comme suit (dans netinet/in.h) pour les systèmes dérivés d'UNIX 4.3BSD :
struct sockaddr_in6 { sa_family_t sin6_family; /* AF_INET6 */ in_port_t sin6_port; /* numéro de port */ uint32_t sin6_flowinfo; /* identificateur de flux */ struct in6_addr sin6_addr; /* adresse IPv6 */ uint32_t sin6_scope_id; /* ensemble d'interfaces correspondant * à la portée de l'adresse */ };
Il faut noter que cette structure a une longueur de 28 octets, et est donc plus grande que le type générique struct sockaddr. Il n'est donc plus possible de réserver une struct sockaddr si la valeur à stocker peut être une struct sockaddr_in6. Afin de faciliter la tâche des implémenteurs, une nouvelle structure de données, struct sockaddr_storage, a été définie. Celle-ci est de taille suffisante afin de pouvoir prendre en compte tous les protocoles supportés et alignée de telle sorte que les conversions de type entre pointeurs vers les structures de données d'adresse des protocoles supportés et pointeurs vers elle-même n'engendrent pas de problèmes d'alignement. Un exemple d'utilisation pourrait être le suivant :
struct sockaddr_storage ss; struct sockaddr_in *sin = (struct sockaddr_in *) &ss; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
Dans la version 4.4 d'UNIX BSD, la longueur du champ sin6_family est passée de 2 octets à 1 octet. L'octet ainsi récupéré contient la taille de la structure sockaddr_in6 et sert à effectuer correctement la conversion de type vers la structure de données générique sockaddr utilisée par bon nombre de primitives de l'interface socket.
La macro-définition SIN6_LEN, présente dans toute implémentation 4.4BSD, permet alors de distinguer les versions. Les autres champs restant inchangés, cette structure est presque identique à celle de la précédente version :
#define SIN6_LEN struct sockaddr_in6 { u_int8_t sin6_len; /* la longueur de cette structure */ sa_family_t sin6_family; /* AF_INET6 */ in_port_t sin6_port; /* numéro de port */ uint32_t sin6_flowinfo; /* identificateur de flux */ struct in6_addr sin6_addr; /* adresse IPv6 */ uint32_t sin6_scope_id; /* ensemble d'interfaces correspondant * à la portée de l'adresse */ };
Si le champ sin6_len existe (ce qui est testable par le fait que le symbole SIN6_LEN est défini), il doit être initialisé par la taille de la structure sockaddr_in6.
On notera la présence de deux nouveaux champs (ils n'ont pas d'équivalents dans la structure sockaddr_in) dans la structure de données sockaddr_in6, les champs sin6_flowinfo et sin6_scope_id. Le premier, en réalité structuré, est décrit dans le RFC 2460 et Identificateur de flux. Le second désigne un ensemble d'interfaces en adéquation avec la portée de l'adresse contenue dans le champ sin6_addr. Par exemple, si l'adresse en question est de type lien local, le champ sin6_scope_id devrait être un index d'interface.