getaddrinfo(3) Library Functions Manual getaddrinfo(3) NOM getaddrinfo, freeaddrinfo, gai_strerror - Traduction d'adresses et de services reseau BIBLIOTHEQUE Bibliotheque C standard (libc, -lc) SYNOPSIS #include #include #include int getaddrinfo(const char *restrict node, const char *restrict service, const struct addrinfo *restrict hints, struct addrinfo **restrict res); void freeaddrinfo(struct addrinfo *res); const char *gai_strerror(int errcode); Exigences de macros de test de fonctionnalites pour la glibc (consulter feature_test_macros(7)) : getaddrinfo(), freeaddrinfo(), gai_strerror() : Avant la glibc 2.22 : _POSIX_C_SOURCE >= 200112L glibc 2.21 et anterieures : _POSIX_C_SOURCE DESCRIPTION Etant donnes node et service, qui identifient un hote Internet et un service, getaddrinfo() renvoie une ou plusieurs structure addrinfo, chacune d'entre elles contenant une adresse Internet qui puisse etre indiquee dans un appel a bind(2) ou connect(2). La fonction getaddrinfo() combine la fonctionnalite fournie par les fonctions gethostbyname(3) et getservbyname(3) en une interface unique, mais a l'inverse de ces fonctions, getaddrinfo() est reentrante et permet aux programmes d'eliminer la dependance envers IPv4 ou IPv6. La structure addrinfo utilisee par getaddrinfo() contient les membres suivants : struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; struct sockaddr *ai_addr; char *ai_canonname; struct addrinfo *ai_next; }; Le parametre hints pointe sur une structure addrinfo qui indique les criteres de selection des structures d'adresses de sockets renvoyees dans la liste pointee par res. Si hints n'est pas NULL, il doit pointer sur une structure addrinfo dont les membres ai_family, ai_socktype, et ai_protocol indiquent les criteres limitant l'ensemble d'adresses de sockets renvoyees par getaddrinfo(), de la facon suivante : ai_family Ce champ indique la famille d'adresse desiree des adresses renvoyees. AF_INET et AF_INET6 font partie des valeurs valables pour ce champ. La valeur AF_UNSPEC indique que getaddrinfo() doit renvoyer les adresses de socket de n'importe quelle famille d'adresses (par exemple, IPv4 ou IPv6) pouvant etre utilisees avec node et service. ai_socktype Ce champ indique le type prefere de socket, par exemple SOCK_STREAM ou SOCK_DGRAM. Mettre 0 dans ce champ indique que getaddrinfo() peut renvoyer n'importe quel type d'adresse de socket. ai_protocol Ce champ indique le protocole des adresses de socket renvoyees. Mettre 0 dans ce champ indique que getaddrinfo() peut renvoyer des adresses de socket de n'importe quel type. ai_flags Ce champ indique des options supplementaires, decrites ci-dessous. Plusieurs attributs peuvent etre indiques en les groupant par un OU binaire. Tous les autres membres de la structure pointee par hints doivent contenir 0 ou etre des pointeurs NULL. Specifier hints a NULL est equivalent a definir ai_socktype et ai_protocol a 0, ai_family a AF_UNSPEC et ai_flags a (AI_V4MAPPED | AI_ADDRCONFIG). (POSIX specifie d'autres valeurs par defaut pour ai_flags ; consultez les NOTES.) node indique soit une adresse reseau en format numerique (decimal pointe pour l'IPv4, comme prise en charge par inet_aton(3) ; hexadecimal pour l'IPv6, comme prise en charge par inet_pton(3)), soit un nom d'hote, dont l'adresse reseau est alors resolue. Si le membre hints.ai_flags contient l'attribut AI_NUMERICHOST alors node devra etre une adresse reseau numerique. L'attribut AI_NUMERICHOST empeche toute tentative, eventuellement longue, de resolution de nom d'hote. Si l'attribut AI_PASSIVE est indique dans hints.ai_flags, et si node est NULL, les adresses de socket renvoyees seront pertinentes pour lier (bind(2)) un socket qui acceptera (accept(2)) les connexions. Les adresses de socket renvoyees contiendront l'<< adresse joker >> (wildcard adress) (INADDR_ANY pour les adresses IPv4, IN6ADDR_ANY_INIT pour les adresses IPv6). L'<< adresse joker >> est utilisee par des applications (typiquement des serveurs) qui ont l'intention d'accepter des connexions de n'importe quel hote. Si node n'est pas NULL, l'attribut AI_PASSIVE est ignore. Si l'attribut AI_PASSIVE n'est pas positionne dans hints.ai_flags, les adresses de socket renvoyees seront pertinentes pour etre utilisees avec connect(2), sendto(2) ou sendmsg(2). Si node est NULL, l'adresse reseau sera definie avec l'adresse de l'interface de boucle (loopback) (INADDR_LOOPBACK pour les adresses IPv4, IN6ADDR_LOOPBACK_INIT pour les adresses IPv6) ; cela est utilise par les applications qui doivent communiquer avec des correspondants s'executant sur la meme machine. service definit le port dans chacune des structures d'adresses renvoyees. Si cet argument est un nom de service (consultez services(5)), il est convertit en son numero de port correspondant. Cet argument peut egalement etre indique sous forme decimale, qui est simplement converti en binaire. Si service est NULL, le numero de port des adresses de socket renvoyees n'est pas initialise. Si AI_NUMERICSERV est indique dans hints.ai_flags et si service n'est pas NULL, service doit pointer vers une chaine contenant une valeur numerique de port. Cet attribut est utilise pour inhiber l'invocation du service de resolution des noms dans les cas ou l'on sait qu'il n'est pas necessaire. node ou service peuvent etre NULL, mais pas les deux a la fois. La fonction getaddrinfo() alloue et initialise une liste chainee de structures addrinfo, une pour chaque adresse reseau correspondant a node et service, soumise aux restrictions imposees par l'argument hints, et renvoie dans res un pointeur sur le debut de la liste. Les elements de la liste sont chaines par le champ ai_next. Il y a plusieurs raisons pour lesquelles la liste chainee peut avoir plus d'une structure addrinfo : l'hote reseau est << multihomed >> ; le meme service est accessible depuis plusieurs protocoles (par exemple AF_INET et AF_INET6) ou accessible depuis plusieurs types de socket (par exemple une adresse de type SOCK_STREAM et une autre de type SOCK_DGRAM). Normalement, l'application essaie d'utiliser les adresses dans l'ordre ou elles sont renvoyees. La fonction de tri utilisee dans getaddrinfo() est definie dans la RFC 3484 ; le tri peut etre configure pour un systeme particulier avec le fichier /etc/gai.conf (disponible depuis la glibc 2.5). Si hints.ai_flags contient l'attribut AI_CANONNAME, le champ ai_canonname de la premiere structure addrinfo de la liste renvoyee est defini pour pointer vers le nom officiel de l'hote. Les champs restants de chaque structure addrinfo renvoyee sont initialises de la facon suivante : - Les champs ai_family, ai_socktype et ai_protocol renvoient les parametres de creation de la socket (c'est-a-dire que ces champs ont la meme signification que les parametres correspondants de socket(2)). Par exemple, ai_family pourrait renvoyer AF_INET ou AF_INET6 ; ai_socktype pourrait renvoyer SOCK_DGRAM ou SOCK_STREAM ; et ai_protocol renvoie le protocole de la socket. - Un pointeur vers l'adresse de la socket est place dans le champ ai_addr, et la longueur de l'adresse de la socket, en octets, est inscrite dans le champ ai_addrlen de la structure. Si hints.ai_flags inclut l'attribut AI_ADDRCONFIG, alors des adresses IPv4 sont renvoyees dans la liste pointee par res seulement si le systeme local possede au moins une adresse IPv4 configuree. Des adresses IPv6 sont seulement renvoyees si le systeme local possede au moins une adresse IPv6 configuree. Dans ce cas, l'adresse de boucle n'est pas consideree comme une adresse configuree valable. Cet attribut est par exemple utile sur les systemes uniquement en IPv4, pour s'assurer que getaddrinfo() ne renvoie pas d'adresse de socket IPv6 qui echouerait toujours dans connect(2) ou bind(2). Si hints.ai_flags indique le drapeau AI_V4MAPPED, et si hints.ai_family a ete indique avec AF_INET6 et qu'aucune adresse IPv6 correspondante n'a pu etre trouvee, alors des adresses IPv4 au format IPv6 sont renvoyees dans la liste pointee par res. Si AI_V4MAPPED et AI_ALL sont indiques dans hints.ai_flags, des adresses IPv6 et des adresses IPv4 au format IPv6 sont renvoyees dans la liste pointee par res. AI_ALL est ignore si AI_V4MAPPED n'est pas aussi indique. La fonction freeaddrinfo() libere la memoire qui a ete allouee dynamiquement pour la liste chainee res. Extensions de getaddrinfo() pour les noms de domaines internationalises Depuis la glibc 2.3.4, getaddrinfo() a ete modifie pour selectivement permettre que les noms d'hotes entrant et sortant soient convertis vers ou depuis le format des noms de domaines internationalises (IDN). Consultez la RFC 3490, Internationalizing Domain Names in Applications (IDNA). Quatre nouveaux attributs ont ete ajoutes : AI_IDN Si cet attribut est defini, alors le nom du noeud contenu dans node est converti dans le format IDN si necessaire. Le format d'encodage choisi est celui de la locale du systeme. Si le nom du noeud contient des caracteres non ASCII, alors le format IDN est utilise. Ces parties du nom du noeud (separees par des points) qui contiennent des caracteres non ASCI sont encodees avec << ASCII Compatible Encoding (ACE) >> avant d'etre transferees aux fonctions de resolution de noms. AI_CANONIDN A la suite d'une resolution de nom reussie et si AI_CANONNAME a ete indique, getaddrinfo() retournera le nom canonique du noeud correspondant a la valeur de la structure addrinfo passee. La valeur renvoyee est une copie exacte de la valeur retournee par la fonction de resolution de noms. Si le nom est encode avec ACE, alors une ou plusieurs composantes de son nom sont prefixees par xn--. Pour convertir ces composantes dans un format lisible, l'attribut AI_CANONIDN peut etre utilise en plus de AI_CANONNAME. La chaine resultante est encodee selon la locale du systeme. AI_IDN_ALLOW_UNASSIGNED AI_IDN_USE_STD3_ASCII_RULES Utiliser ces attributs permet d'activer respectivement les attributs << IDNA_ALLOW_UNASSIGNED >> (permettre des caracteres Unicode non assignes) et << IDNA_USE_STD3_ASCII_RULES >> (verifier la sortie pour etre sur que le nom d'hote est conforme a STD3) utilises dans la gestion de l'IDNA. VALEUR RENVOYEE getaddrinfo() renvoie 0 si elle reussit, ou l'un des codes d'erreur different de suivants : EAI_ADDRFAMILY L'hote indique n'a pas d'adresse dans la famille reseau demandee. EAI_AGAIN Le serveur de noms a renvoye une erreur temporaire. Reessayez plus tard. EAI_BADFLAGS hints.ai_flags contient des drapeaux incorrects ; ou hints.ai_flags inclut AI_CANONNAME et name est NULL. EAI_FAIL Le serveur de noms a renvoye une erreur definitive. EAI_FAMILY La famille d'adresse reclamee n'est pas supportee. EAI_MEMORY Plus assez de memoire. EAI_NODATA L'hote existe mais n'a pas d'adresse reseau definie. EAI_NONAME node ou service sont inconnus ou ils sont tous les deux NULL ; ou AI_NUMERICSERV a ete indique dans hints.ai_flags mais service n'est pas un numero de port. EAI_SERVICE Le service demande n'est pas disponible pour le type de socket demande. Il est probablement disponible avec un autre type de socket. Par exemple, cette erreur peut se produire si service est << shell >> (un service uniquement disponible avec les sockets de type flux), et soit si hints.ai_protocol est egal a IPPROTO_UDP ou soit si hints.ai_socktype est egal a SOCK_DGRAM. L'erreur peut aussi se produire si service est non NULL et hints.ai_socktype est egal a SOCK_RAW (un type de socket qui ne gere pas le concept de service). EAI_SOCKTYPE Le type de socket demande n'est pas gere. Cela peut se produire, par exemple si hints.ai_socktype et hints.ai_protocol sont inconsistants (par exemple, SOCK_DGRAM et IPPROTO_TCP, respectivement). EAI_SYSTEM Autre erreur systeme, la valeur de retour est -1 et errno est defini pour indiquer l'erreur. La fonction gai_strerror() traduit ces codes d'erreur en une chaine de caracteres comprehensible, utilisable pour rendre compte du probleme. FICHIERS /etc/gai.conf ATTRIBUTS Pour une explication des termes utilises dans cette section, consulter attributes(7). +----------------------+--------------------------+--------------------+ |Interface | Attribut | Valeur | +----------------------+--------------------------+--------------------+ |getaddrinfo() | Securite des threads | MT-Safe env locale | +----------------------+--------------------------+--------------------+ |freeaddrinfo(), | Securite des threads | MT-Safe | |gai_strerror() | | | +----------------------+--------------------------+--------------------+ VERSIONS Selon POSIX.1, definir hints comme NULL devrait supposer que ai_flags soit egal a 0. La bibliotheque C de GNU suppose a la place que ai_flags est egal a (AI_V4MAPPED | AI_ADDRCONFIG) dans ce cas, puisque cette valeur est consideree comme une amelioration de la specification. STANDARDS POSIX.1-2008. getaddrinfo() RFC 2553. HISTORIQUE POSIX.1-2001. AI_ADDRCONFIG AI_ALL AI_V4MAPPED glibc 2.3.3. AI_NUMERICSERV glibc 2.3.4. NOTES getaddrinfo() gere la notation address%scope-id pour indiquer l'identifiant scope de IPv6. EXEMPLES Le programme suivant explique l'utilisation de getaddrinfo(), gai_strerror(), freeaddrinfo(), et getnameinfo(3). Les programmes sont des clients et serveurs pour les datagrammes UDP. Programme du serveur #include #include #include #include #include #include #include #define BUF_SIZE 500 int main(int argc, char *argv[]) { int sfd, s; char buf[BUF_SIZE]; ssize_t nread; socklen_t peer_addrlen; struct addrinfo hints; struct addrinfo *result, *rp; struct sockaddr_storage peer_addr; if (argc != 2) { fprintf(stderr, "Utilisation : %s port\n", argv[0]); exit(EXIT_FAILURE); } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* IPv4 ou IPv6 permis */ hints.ai_socktype = SOCK_DGRAM; /* Socket du datagramme */ hints.ai_flags = AI_PASSIVE; /* Pour une adresse IP joker */ hints.ai_protocol = 0; /* Tout protocole */ hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; s = getaddrinfo(NULL, argv[1], &hints, &result); if (s != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); exit(EXIT_FAILURE); } /* getaddrinfo() renvoie une liste de structures d'adresse. Essayer cheque adresse jusqu'a un bind(2) reussi. Si socket(2) (ou bind(2)) echoue, on (clot le socket et) essaie l'adresse suivante. */ for (rp = result; rp != NULL; rp = rp->ai_next) { sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sfd == -1) continue; if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) break; /* Succes */ close(sfd); } freeaddrinfo(result); /* Plus necessaire */ if (rp == NULL) { /* Toutes les adresses ont echoue */ fprintf(stderr, "Pas de lien cree\n"); exit(EXIT_FAILURE); } /* Lire les datagrammes et les renvoyer a l'envoyeur. */ for (;;) { char host[NI_MAXHOST], service[NI_MAXSERV]; peer_addrlen = sizeof(peer_addr); nread = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &peer_addr, &peer_addrlen); if (nread == -1) continue; /* Ignorer la requete en echec */ s = getnameinfo((struct sockaddr *) &peer_addr, peer_addrlen, host, NI_MAXHOST, service, NI_MAXSERV, NI_NUMERICSERV); if (s == 0) printf("%zd octets recus de %s:%s\n", nread, host, service); else fprintf(stderr, "getnameinfo : %s\n", gai_strerror(s)); if (sendto(sfd, buf, nread, 0, (struct sockaddr *) &peer_addr, peer_addrlen) != nread) { fprintf(stderr, "Erreur d'envoi de reponse\n"); } } } Programme du client #include #include #include #include #include #include #include #define BUF_SIZE 500 int main(int argc, char *argv[]) { int sfd, s; char buf[BUF_SIZE]; size_t len; ssize_t nread; struct addrinfo hints; struct addrinfo *result, *rp; if (argc < 3) { fprintf(stderr, "Utilisation : %s host port msg...\n", argv[0]); exit(EXIT_FAILURE); } /* Obtenir les adresses correspondantes hote/port. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* IPv4 ou IPv6 permis */ hints.ai_socktype = SOCK_DGRAM; /* Socket du datagramme */ hints.ai_flags = 0; hints.ai_protocol = 0; /* Tout protocole */ s = getaddrinfo(argv[1], argv[2], &hints, &result); if (s != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); exit(EXIT_FAILURE); } /* getaddrinfo() renvoie une liste de structures d'adresse. Essayer chaque adresse jusqu'a un bind(2) reussi. Si socket(2) (ou bind(2)) echoue, on (clot le socket et) essaie l'adresse suivante. */ for (rp = result; rp != NULL; rp = rp->ai_next) { sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sfd == -1) continue; if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) break; /* Succes */ close(sfd); } freeaddrinfo(result); /* Plus necessaire */ if (rp == NULL) { /* Toutes les adresses ont echoue */ fprintf(stderr, "Connexion impossible\n"); exit(EXIT_FAILURE); } /* Envoyer les arguments en ligne de commande comme des datagrammes separes et lire les reponses du serveur. */ for (size_t j = 3; j < argc; j++) { len = strlen(argv[j]) + 1; /* +1 pour l'octet NULL de terminaison */ if (len > BUF_SIZE) { fprintf(stderr, "Ignorer le message long dans l'argument %zu\n", j); continue; } if (write(sfd, argv[j], len) != len) { fprintf(stderr, "ecriture partielle/echec\n"); exit(EXIT_FAILURE); } nread = read(sfd, buf, BUF_SIZE); if (nread == -1) { perror("read"); exit(EXIT_FAILURE); } printf("%zd octets recus de : %s\n", nread, buf); } exit(EXIT_SUCCESS); } VOIR AUSSI getaddrinfo_a(3), gethostbyname(3), getnameinfo(3), inet(3), gai.conf(5), hostname(7), ip(7) TRADUCTION La traduction francaise de cette page de manuel a ete creee par Christophe Blaess , Stephan Rafin , Thierry Vignaud , Francois Micaux, Alain Portal , Jean-Philippe Guerard , Jean-Luc Coulon (f5ibh) , Julien Cristau , Thomas Huriaux , Nicolas Francois , Florentin Duneau , Simon Paillard , Denis Barbier , David Prevot et Jean-Pierre Giraud Cette traduction est une documentation libre ; veuillez vous reporter a la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITE LEGALE. Si vous decouvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message a . Pages du manuel de Linux 6.06 31 octobre 2023 getaddrinfo(3)