getaddrinfo(3) | Library Functions Manual | getaddrinfo(3) |
getaddrinfo, freeaddrinfo, gai_strerror - Traduction d'adresses et de services réseau
Bibliothèque C standard (libc, -lc)
#include <sys/types.h> #include <sys/socket.h> #include <netdb.h>
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);
getaddrinfo(), freeaddrinfo(), gai_strerror() :
Depuis la glibc 2.22 :
_POSIX_C_SOURCE >= 200112L
glibc 2.21 et antérieure :
_POSIX_C_SOURCE
Étant donnés node et service, qui identifient un hôte Internet et un service, getaddrinfo() renvoie une ou plusieurs structure addrinfo, chacune d'entre elles contenant une adresse Internet qui puisse être indiquée dans un appel à bind(2) ou connect(2). La fonction getaddrinfo() combine la fonctionnalité fournie par les fonctions gethostbyname(3) et getservbyname(3) en une interface unique, mais à l'inverse de ces fonctions, getaddrinfo() est réentrante et permet aux programmes d'éliminer la dépendance envers IPv4 ou IPv6.
La structure addrinfo utilisée 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 paramètre hints pointe sur une structure addrinfo qui indique les critères de sélection des structures d'adresses de sockets renvoyées dans la liste pointée 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 critères limitant l'ensemble d'adresses de sockets renvoyées par getaddrinfo(), de la façon suivante :
Tous les autres membres de la structure pointée par hints doivent contenir 0 ou être des pointeurs NULL.
Spécifier hints à NULL est équivalent à définir ai_socktype et ai_protocol à 0, ai_family à AF_UNSPEC et ai_flags à (AI_V4MAPPED | AI_ADDRCONFIG). (POSIX spécifie d'autres valeurs par défaut pour ai_flags ; consultez les NOTES.) node indique soit une adresse réseau en format numérique (décimal pointé pour l'IPv4, comme prise en charge par inet_aton(3) ; hexadécimal pour l'IPv6, comme prise en charge par inet_pton(3)), soit un nom d'hôte, dont l'adresse réseau est alors résolue. Si le membre hints.ai_flags contient l'attribut AI_NUMERICHOST alors node devra être une adresse réseau numérique. L'attribut AI_NUMERICHOST empêche toute tentative, éventuellement longue, de résolution de nom d'hôte.
Si l'attribut AI_PASSIVE est indiqué dans hints.ai_flags, et si node est NULL, les adresses de socket renvoyées seront pertinentes pour lier (bind(2)) un socket qui acceptera (accept(2)) les connexions. Les adresses de socket renvoyées contiendront l'« adresse joker » (wildcard adress) (INADDR_ANY pour les adresses IPv4, IN6ADDR_ANY_INIT pour les adresses IPv6). L'« adresse joker » est utilisée par des applications (typiquement des serveurs) qui ont l'intention d'accepter des connexions de n'importe quel hôte. Si node n'est pas NULL, l'attribut AI_PASSIVE est ignoré.
Si l'attribut AI_PASSIVE n'est pas positionné dans hints.ai_flags, les adresses de socket renvoyées seront pertinentes pour être utilisées avec connect(2), sendto(2) ou sendmsg(2). Si node est NULL, l'adresse réseau sera définie avec l'adresse de l'interface de boucle (loopback) (INADDR_LOOPBACK pour les adresses IPv4, IN6ADDR_LOOPBACK_INIT pour les adresses IPv6) ; cela est utilisé par les applications qui doivent communiquer avec des correspondants s'exécutant sur la même machine.
service définit le port dans chacune des structures d'adresses renvoyées. Si cet argument est un nom de service (consultez services(5)), il est convertit en son numéro de port correspondant. Cet argument peut également être indiqué sous forme décimale, qui est simplement converti en binaire. Si service est NULL, le numéro de port des adresses de socket renvoyées n'est pas initialisé. Si AI_NUMERICSERV est indiqué dans hints.ai_flags et si service n'est pas NULL, service doit pointer vers une chaîne contenant une valeur numérique de port. Cet attribut est utilisé pour inhiber l'invocation du service de résolution des noms dans les cas où l'on sait qu'il n'est pas nécessaire.
node ou service peuvent être NULL, mais pas les deux à la fois.
La fonction getaddrinfo() alloue et initialise une liste chaînée de structures addrinfo, une pour chaque adresse réseau correspondant à node et service, soumise aux restrictions imposées par l'argument hints, et renvoie dans res un pointeur sur le début de la liste. Les éléments de la liste sont chaînés par le champ ai_next.
Il y a plusieurs raisons pour lesquelles la liste chaînée peut avoir plus d'une structure addrinfo : l'hôte réseau est « multihomed » ; le même 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 où elles sont renvoyées. La fonction de tri utilisée dans getaddrinfo() est définie dans la RFC 3484 ; le tri peut être configuré pour un système 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 première structure addrinfo de la liste renvoyée est défini pour pointer vers le nom officiel de l'hôte.
Les champs restants de chaque structure addrinfo renvoyée sont initialisés de la façon suivante :
Si hints.ai_flags inclut l'attribut AI_ADDRCONFIG, alors des adresses IPv4 sont renvoyées dans la liste pointée par res seulement si le système local possède au moins une adresse IPv4 configurée. Des adresses IPv6 sont seulement renvoyées si le système local possède au moins une adresse IPv6 configurée. Dans ce cas, l'adresse de boucle n'est pas considérée comme une adresse configurée valable. Cet attribut est par exemple utile sur les systèmes uniquement en IPv4, pour s’assurer que getaddrinfo() ne renvoie pas d’adresse de socket IPv6 qui échouerait toujours dans connect(2) ou bind(2).
Si hints.ai_flags indique le drapeau AI_V4MAPPED, et si hints.ai_family a été indiqué avec AF_INET6 et qu'aucune adresse IPv6 correspondante n'a pu être trouvée, alors des adresses IPv4 au format IPv6 sont renvoyées dans la liste pointée par res. Si AI_V4MAPPED et AI_ALL sont indiqués dans hints.ai_flags, des adresses IPv6 et des adresses IPv4 au format IPv6 sont renvoyées dans la liste pointée par res. AI_ALL est ignoré si AI_V4MAPPED n'est pas aussi indiqué.
La fonction freeaddrinfo() libère la mémoire qui a été allouée dynamiquement pour la liste chaînée res.
Depuis la glibc 2.3.4, getaddrinfo() a été modifié pour sélectivement permettre que les noms d'hôtes entrant et sortant soient convertis vers ou depuis le format des noms de domaines internationalisés (IDN). Consultez la RFC 3490, Internationalizing Domain Names in Applications (IDNA). Quatre nouveaux attributs ont été ajoutés :
getaddrinfo() renvoie 0 si elle réussit, ou l'un des codes d'erreur non nuls suivants :
La fonction gai_strerror() traduit ces codes d'erreur en une chaîne de caractères compréhensible, utilisable pour rendre compte du problème.
/etc/gai.conf
Pour une explication des termes utilisés dans cette section, consulter attributes(7).
Interface | Attribut | Valeur |
getaddrinfo() | Sécurité des threads | MT-Safe env locale |
freeaddrinfo(), gai_strerror() | Sécurité des threads | MT-Safe |
POSIX.1-2001, POSIX.1-2008. La fonction getaddrinfo() est documentée dans la RFC 2553.
getaddrinfo() gère la notation address%scope-id pour indiquer l'identifiant scope de IPv6.
AI_ADDRCONFIG, AI_ALL et AI_V4MAPPED sont disponibles depuis la glibc 2.3.3. AI_NUMERICSERV est disponible depuis la glibc 2.3.4.
Selon POSIX.1, définir hints comme NULL devrait supposer que ai_flags soit égal à 0. La bibliothèque C de GNU suppose à la place que ai_flags est égal à (AI_V4MAPPED | AI_ADDRCONFIG) dans ce cas, puisque cette valeur est considérée comme une amélioration de la spécification.
Le programme suivant explique l'utilisation de getaddrinfo(), gai_strerror(), freeaddrinfo(), et getnameinfo(3). Les programmes sont des clients et serveurs
#include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #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, "Usage: %s port\n", argv[0]);
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
hints.ai_protocol = 0; /* Any protocol */
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() returns a list of address structures.
Try each address until we successfully bind(2).
If socket(2) (or bind(2)) fails, we (close the socket
and) try the next address. */
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; /* Success */
close(sfd);
}
freeaddrinfo(result); /* No longer needed */
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not bind\n");
exit(EXIT_FAILURE);
}
/* Read datagrams and echo them back to sender. */
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; /* Ignore failed request */
s = getnameinfo((struct sockaddr *) &peer_addr,
peer_addrlen, host, NI_MAXHOST,
service, NI_MAXSERV, NI_NUMERICSERV);
if (s == 0)
printf("Received %zd bytes from %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, "Error sending response\n");
}
} }
#include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #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, "Usage: %s host port msg...\n", argv[0]);
exit(EXIT_FAILURE);
}
/* Obtain address(es) matching host/port. */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
s = getaddrinfo(argv[1], argv[2], &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully connect(2).
If socket(2) (or connect(2)) fails, we (close the socket
and) try the next address. */
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; /* Success */
close(sfd);
}
freeaddrinfo(result); /* No longer needed */
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not connect\n");
exit(EXIT_FAILURE);
}
/* Send remaining command-line arguments as separate
datagrams, and read responses from server. */
for (size_t j = 3; j < argc; j++) {
len = strlen(argv[j]) + 1;
/* +1 for terminating null byte */
if (len > BUF_SIZE) {
fprintf(stderr,
"Ignoring long message in argument %zu\n", j);
continue;
}
if (write(sfd, argv[j], len) != len) {
fprintf(stderr, "partial/failed write\n");
exit(EXIT_FAILURE);
}
nread = read(sfd, buf, BUF_SIZE);
if (nread == -1) {
perror("read");
exit(EXIT_FAILURE);
}
printf("Received %zd bytes: %s\n", nread, buf);
}
exit(EXIT_SUCCESS); }
getaddrinfo_a(3), gethostbyname(3), getnameinfo(3), inet(3), gai.conf(5), hostname(7), ip(7)
La traduction française de cette page de manuel a été créée par Christophe Blaess <https://www.blaess.fr/christophe/>, Stéphan Rafin <stephan.rafin@laposte.net>, Thierry Vignaud <tvignaud@mandriva.com>, François Micaux, Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe Guérard <fevrier@tigreraye.org>, Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>, Julien Cristau <jcristau@debian.org>, Thomas Huriaux <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin Duneau <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>, Denis Barbier <barbier@debian.org> et David Prévot <david@tilapin.org>
Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à debian-l10n-french@lists.debian.org.
5 février 2023 | Pages du manuel de Linux 6.03 |