(gaih_inet): Really set ai_canonname only in one entry.
[glibc.git] / sysdeps / posix / getaddrinfo.c
blobef32e68f01a04f03aaca12ccac422960716369ae
1 /* The Inner Net License, Version 2.00
3 The author(s) grant permission for redistribution and use in source and
4 binary forms, with or without modification, of the software and documentation
5 provided that the following conditions are met:
7 0. If you receive a version of the software that is specifically labelled
8 as not being for redistribution (check the version message and/or README),
9 you are not permitted to redistribute that version of the software in any
10 way or form.
11 1. All terms of the all other applicable copyrights and licenses must be
12 followed.
13 2. Redistributions of source code must retain the authors' copyright
14 notice(s), this list of conditions, and the following disclaimer.
15 3. Redistributions in binary form must reproduce the authors' copyright
16 notice(s), this list of conditions, and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18 4. [The copyright holder has authorized the removal of this clause.]
19 5. Neither the name(s) of the author(s) nor the names of its contributors
20 may be used to endorse or promote products derived from this software
21 without specific prior written permission.
23 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
24 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
27 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 If these license terms cause you a real problem, contact the author. */
36 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
38 #include <assert.h>
39 #include <errno.h>
40 #include <ifaddrs.h>
41 #include <netdb.h>
42 #include <resolv.h>
43 #include <stdbool.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <arpa/inet.h>
49 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <sys/types.h>
52 #include <sys/un.h>
53 #include <sys/utsname.h>
54 #include <net/if.h>
55 #include <nsswitch.h>
56 #include <not-cancel.h>
58 #ifdef HAVE_LIBIDN
59 extern int __idna_to_ascii_lz (const char *input, char **output, int flags);
60 extern int __idna_to_unicode_lzlz (const char *input, char **output,
61 int flags);
62 # include <libidn/idna.h>
63 #endif
65 #define GAIH_OKIFUNSPEC 0x0100
66 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
68 #ifndef UNIX_PATH_MAX
69 #define UNIX_PATH_MAX 108
70 #endif
72 struct gaih_service
74 const char *name;
75 int num;
78 struct gaih_servtuple
80 struct gaih_servtuple *next;
81 int socktype;
82 int protocol;
83 int port;
86 static const struct gaih_servtuple nullserv;
88 struct gaih_addrtuple
90 struct gaih_addrtuple *next;
91 int family;
92 char addr[16];
93 uint32_t scopeid;
96 struct gaih_typeproto
98 int socktype;
99 int protocol;
100 char name[4];
101 int protoflag;
104 /* Values for `protoflag'. */
105 #define GAI_PROTO_NOSERVICE 1
106 #define GAI_PROTO_PROTOANY 2
108 static const struct gaih_typeproto gaih_inet_typeproto[] =
110 { 0, 0, "", 0 },
111 { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
112 { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
113 { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
114 { 0, 0, "", 0 }
117 struct gaih
119 int family;
120 int (*gaih)(const char *name, const struct gaih_service *service,
121 const struct addrinfo *req, struct addrinfo **pai);
124 static const struct addrinfo default_hints =
126 .ai_flags = AI_DEFAULT,
127 .ai_family = PF_UNSPEC,
128 .ai_socktype = 0,
129 .ai_protocol = 0,
130 .ai_addrlen = 0,
131 .ai_addr = NULL,
132 .ai_canonname = NULL,
133 .ai_next = NULL
137 #if 0
138 /* Using Unix sockets this way is a security risk. */
139 static int
140 gaih_local (const char *name, const struct gaih_service *service,
141 const struct addrinfo *req, struct addrinfo **pai)
143 struct utsname utsname;
145 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
146 return GAIH_OKIFUNSPEC | -EAI_NONAME;
148 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
149 if (uname (&utsname) < 0)
150 return -EAI_SYSTEM;
152 if (name != NULL)
154 if (strcmp(name, "localhost") &&
155 strcmp(name, "local") &&
156 strcmp(name, "unix") &&
157 strcmp(name, utsname.nodename))
158 return GAIH_OKIFUNSPEC | -EAI_NONAME;
161 if (req->ai_protocol || req->ai_socktype)
163 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
165 while (tp->name[0]
166 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
167 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
168 || (req->ai_protocol != 0
169 && !(tp->protoflag & GAI_PROTO_PROTOANY)
170 && req->ai_protocol != tp->protocol)))
171 ++tp;
173 if (! tp->name[0])
175 if (req->ai_socktype)
176 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
177 else
178 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
182 *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
183 + ((req->ai_flags & AI_CANONNAME)
184 ? (strlen(utsname.nodename) + 1): 0));
185 if (*pai == NULL)
186 return -EAI_MEMORY;
188 (*pai)->ai_next = NULL;
189 (*pai)->ai_flags = req->ai_flags;
190 (*pai)->ai_family = AF_LOCAL;
191 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
192 (*pai)->ai_protocol = req->ai_protocol;
193 (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
194 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
196 #if SALEN
197 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
198 sizeof (struct sockaddr_un);
199 #endif /* SALEN */
201 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
202 memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
204 if (service)
206 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
208 if (strchr (service->name, '/') != NULL)
210 if (strlen (service->name) >= sizeof (sunp->sun_path))
211 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
213 strcpy (sunp->sun_path, service->name);
215 else
217 if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
218 sizeof (sunp->sun_path))
219 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
221 __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
224 else
226 /* This is a dangerous use of the interface since there is a time
227 window between the test for the file and the actual creation
228 (done by the caller) in which a file with the same name could
229 be created. */
230 char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
232 if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
233 0) != 0
234 || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
235 return -EAI_SYSTEM;
238 if (req->ai_flags & AI_CANONNAME)
239 (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
240 + sizeof (struct sockaddr_un),
241 utsname.nodename);
242 else
243 (*pai)->ai_canonname = NULL;
244 return 0;
246 #endif /* 0 */
248 static int
249 gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
250 const struct addrinfo *req, struct gaih_servtuple *st)
252 struct servent *s;
253 size_t tmpbuflen = 1024;
254 struct servent ts;
255 char *tmpbuf;
256 int r;
260 tmpbuf = __alloca (tmpbuflen);
262 r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
263 &s);
264 if (r != 0 || s == NULL)
266 if (r == ERANGE)
267 tmpbuflen *= 2;
268 else
269 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
272 while (r);
274 st->next = NULL;
275 st->socktype = tp->socktype;
276 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
277 ? req->ai_protocol : tp->protocol);
278 st->port = s->s_port;
280 return 0;
283 #define gethosts(_family, _type) \
285 int i, herrno; \
286 size_t tmpbuflen; \
287 struct hostent th; \
288 char *tmpbuf = NULL; \
289 tmpbuflen = 512; \
290 no_data = 0; \
291 do { \
292 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \
293 rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \
294 tmpbuflen, &h, &herrno); \
295 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
296 if (rc != 0) \
298 if (herrno == NETDB_INTERNAL) \
300 __set_h_errno (herrno); \
301 return -EAI_SYSTEM; \
303 if (herrno == TRY_AGAIN) \
304 no_data = EAI_AGAIN; \
305 else \
306 no_data = herrno == NO_DATA; \
308 else if (h != NULL) \
310 for (i = 0; h->h_addr_list[i]; i++) \
312 if (*pat == NULL) { \
313 *pat = __alloca (sizeof (struct gaih_addrtuple)); \
314 (*pat)->scopeid = 0; \
316 (*pat)->next = NULL; \
317 (*pat)->family = _family; \
318 memcpy ((*pat)->addr, h->h_addr_list[i], \
319 sizeof(_type)); \
320 pat = &((*pat)->next); \
322 if (_family == AF_INET6) \
323 got_ipv6 = true; \
325 else if (_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED)) \
327 /* We have to add V4 mapped addresses. Maybe we discard them \
328 later again but we get them anyhow for now. */ \
329 while ((rc = __gethostbyname2_r (name, AF_INET6, &th, tmpbuf, \
330 tmpbuflen, &h, &herrno)) == ERANGE \
331 && herrno == NETDB_INTERNAL) \
332 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \
334 if (rc != 0) \
336 if (herrno == NETDB_INTERNAL) \
338 __set_h_errno (herrno); \
339 return -EAI_SYSTEM; \
341 if (herrno == TRY_AGAIN) \
342 no_data = EAI_AGAIN; \
343 else \
344 no_data = herrno == NO_DATA; \
346 else if (h != NULL) \
348 for (i = 0; h->h_addr_list[i]; ++i) \
350 if (*pat == NULL) \
352 *pat = __alloca (sizeof (struct gaih_addrtuple)); \
353 (*pat)->scopeid = 0; \
355 uint32_t *addr = (uint32_t *) (*pat)->addr; \
356 (*pat)->next = NULL; \
357 (*pat)->family = _family; \
358 addr[3] = *(uint32_t *) h->h_addr_list[i]; \
359 addr[2] = htonl (0xffff); \
360 addr[1] = 0; \
361 addr[0] = 0; \
362 pat = &((*pat)->next); \
369 #define gethosts2(_family, _type) \
371 int i, herrno; \
372 size_t tmpbuflen; \
373 struct hostent th; \
374 char *tmpbuf = NULL; \
375 tmpbuflen = 512; \
376 no_data = 0; \
377 do { \
378 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \
379 rc = 0; \
380 status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf, \
381 tmpbuflen, &rc, &herrno)); \
382 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
383 if (status == NSS_STATUS_SUCCESS && rc == 0) \
384 h = &th; \
385 else \
386 h = NULL; \
387 if (rc != 0) \
389 if (herrno == NETDB_INTERNAL) \
391 __set_h_errno (herrno); \
392 return -EAI_SYSTEM; \
394 if (herrno == TRY_AGAIN) \
395 no_data = EAI_AGAIN; \
396 else \
397 no_data = herrno == NO_DATA; \
399 else if (h != NULL) \
401 for (i = 0; h->h_addr_list[i]; i++) \
403 if (*pat == NULL) { \
404 *pat = __alloca (sizeof (struct gaih_addrtuple)); \
405 (*pat)->scopeid = 0; \
407 (*pat)->next = NULL; \
408 (*pat)->family = _family; \
409 memcpy ((*pat)->addr, h->h_addr_list[i], \
410 sizeof(_type)); \
411 pat = &((*pat)->next); \
416 typedef enum nss_status (*nss_gethostbyname2_r)
417 (const char *name, int af, struct hostent *host,
418 char *buffer, size_t buflen, int *errnop,
419 int *h_errnop);
420 extern service_user *__nss_hosts_database attribute_hidden;
422 static int
423 gaih_inet (const char *name, const struct gaih_service *service,
424 const struct addrinfo *req, struct addrinfo **pai)
426 const struct gaih_typeproto *tp = gaih_inet_typeproto;
427 struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
428 struct gaih_addrtuple *at = NULL;
429 int rc;
430 bool got_ipv6 = false;
432 if (req->ai_protocol || req->ai_socktype)
434 ++tp;
436 while (tp->name[0]
437 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
438 || (req->ai_protocol != 0
439 && !(tp->protoflag & GAI_PROTO_PROTOANY)
440 && req->ai_protocol != tp->protocol)))
441 ++tp;
443 if (! tp->name[0])
445 if (req->ai_socktype)
446 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
447 else
448 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
452 if (service != NULL)
454 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
455 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
457 if (service->num < 0)
459 if (tp->name[0])
461 st = (struct gaih_servtuple *)
462 __alloca (sizeof (struct gaih_servtuple));
464 if ((rc = gaih_inet_serv (service->name, tp, req, st)))
465 return rc;
467 else
469 struct gaih_servtuple **pst = &st;
470 for (tp++; tp->name[0]; tp++)
472 struct gaih_servtuple *newp;
474 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
475 continue;
477 if (req->ai_socktype != 0
478 && req->ai_socktype != tp->socktype)
479 continue;
480 if (req->ai_protocol != 0
481 && !(tp->protoflag & GAI_PROTO_PROTOANY)
482 && req->ai_protocol != tp->protocol)
483 continue;
485 newp = (struct gaih_servtuple *)
486 __alloca (sizeof (struct gaih_servtuple));
488 if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
490 if (rc & GAIH_OKIFUNSPEC)
491 continue;
492 return rc;
495 *pst = newp;
496 pst = &(newp->next);
498 if (st == (struct gaih_servtuple *) &nullserv)
499 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
502 else
504 st = __alloca (sizeof (struct gaih_servtuple));
505 st->next = NULL;
506 st->socktype = tp->socktype;
507 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
508 ? req->ai_protocol : tp->protocol);
509 st->port = htons (service->num);
512 else if (req->ai_socktype || req->ai_protocol)
514 st = __alloca (sizeof (struct gaih_servtuple));
515 st->next = NULL;
516 st->socktype = tp->socktype;
517 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
518 ? req->ai_protocol : tp->protocol);
519 st->port = 0;
521 else
523 /* Neither socket type nor protocol is set. Return all socket types
524 we know about. */
525 struct gaih_servtuple **lastp = &st;
526 for (++tp; tp->name[0]; ++tp)
528 struct gaih_servtuple *newp;
530 newp = __alloca (sizeof (struct gaih_servtuple));
531 newp->next = NULL;
532 newp->socktype = tp->socktype;
533 newp->protocol = tp->protocol;
534 newp->port = 0;
536 *lastp = newp;
537 lastp = &newp->next;
541 if (name != NULL)
543 at = __alloca (sizeof (struct gaih_addrtuple));
545 at->family = AF_UNSPEC;
546 at->scopeid = 0;
547 at->next = NULL;
549 #ifdef HAVE_LIBIDN
550 if (req->ai_flags & AI_IDN)
552 int idn_flags = 0;
553 if (req->ai_flags & AI_IDN_ALLOW_UNASSIGNED)
554 idn_flags |= IDNA_ALLOW_UNASSIGNED;
555 if (req->ai_flags & AI_IDN_USE_STD3_ASCII_RULES)
556 idn_flags |= IDNA_USE_STD3_ASCII_RULES;
558 char *p = NULL;
559 rc = __idna_to_ascii_lz (name, &p, idn_flags);
560 if (rc != IDNA_SUCCESS)
562 if (rc == IDNA_MALLOC_ERROR)
563 return -EAI_MEMORY;
564 if (rc == IDNA_DLOPEN_ERROR)
565 return -EAI_SYSTEM;
566 return -EAI_IDN_ENCODE;
568 /* In case the output string is the same as the input string
569 no new string has been allocated. */
570 if (p != name)
572 name = strdupa (p);
573 free (p);
576 #endif
578 if (__inet_aton (name, (struct in_addr *) at->addr) != 0)
580 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
581 at->family = AF_INET;
582 else if (req->ai_family == AF_INET6 && req->ai_flags & AI_V4MAPPED)
584 ((uint32_t *) at->addr)[3] = *(uint32_t *) at->addr;
585 ((uint32_t *) at->addr)[2] = htonl (0xffff);
586 ((uint32_t *) at->addr)[1] = 0;
587 ((uint32_t *) at->addr)[0] = 0;
588 at->family = AF_INET6;
590 else
591 return -EAI_ADDRFAMILY;
594 if (at->family == AF_UNSPEC)
596 char *namebuf = strdupa (name);
597 char *scope_delim;
599 scope_delim = strchr (namebuf, SCOPE_DELIMITER);
600 if (scope_delim != NULL)
601 *scope_delim = '\0';
603 if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
605 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
606 at->family = AF_INET6;
607 else if (req->ai_family == AF_INET
608 && IN6_IS_ADDR_V4MAPPED (at->addr))
610 *(uint32_t *) at->addr = ((uint32_t *) at->addr)[3];
611 at->family = AF_INET;
613 else
614 return -EAI_ADDRFAMILY;
616 if (scope_delim != NULL)
618 int try_numericscope = 0;
619 if (IN6_IS_ADDR_LINKLOCAL (at->addr)
620 || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
622 at->scopeid = if_nametoindex (scope_delim + 1);
623 if (at->scopeid == 0)
624 try_numericscope = 1;
626 else
627 try_numericscope = 1;
629 if (try_numericscope != 0)
631 char *end;
632 assert (sizeof (uint32_t) <= sizeof (unsigned long));
633 at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
634 10);
635 if (*end != '\0')
636 return GAIH_OKIFUNSPEC | -EAI_NONAME;
642 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
644 struct hostent *h;
645 struct gaih_addrtuple **pat = &at;
646 int no_data = 0;
647 int no_inet6_data = 0;
648 /* If we are looking for both IPv4 and IPv6 address we don't
649 want the lookup functions to automatically promote IPv4
650 addresses to IPv6 addresses. Currently this is decided
651 by setting the RES_USE_INET6 bit in _res.options. */
652 if (req->ai_family == AF_UNSPEC)
654 service_user *nip = NULL;
655 enum nss_status inet6_status, status = NSS_STATUS_UNAVAIL;
656 int no_more;
657 nss_gethostbyname2_r fct;
658 int old_res_options;
660 if (__nss_hosts_database != NULL)
662 no_more = 0;
663 nip = __nss_hosts_database;
665 else
666 no_more = __nss_database_lookup ("hosts", NULL,
667 "dns [!UNAVAIL=return] files",
668 &nip);
670 if (__res_maybe_init (&_res, 0) == -1)
671 no_more = 1;
672 old_res_options = _res.options;
673 _res.options &= ~RES_USE_INET6;
675 while (!no_more)
677 fct = __nss_lookup_function (nip, "gethostbyname2_r");
679 if (fct != NULL)
681 gethosts2 (AF_INET6, struct in6_addr);
682 no_inet6_data = no_data;
683 inet6_status = status;
684 gethosts2 (AF_INET, struct in_addr);
686 /* If we found one address for AF_INET or AF_INET6,
687 don't continue the search. */
688 if (inet6_status == NSS_STATUS_SUCCESS ||
689 status == NSS_STATUS_SUCCESS)
690 break;
692 /* We can have different states for AF_INET
693 and AF_INET6. Try to find a usefull one for
694 both. */
695 if (inet6_status == NSS_STATUS_TRYAGAIN)
696 status = NSS_STATUS_TRYAGAIN;
697 else if (status == NSS_STATUS_UNAVAIL &&
698 inet6_status != NSS_STATUS_UNAVAIL)
699 status = inet6_status;
702 if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
703 break;
705 if (nip->next == NULL)
706 no_more = -1;
707 else
708 nip = nip->next;
711 _res.options = old_res_options;
713 else if (req->ai_family == AF_INET6)
715 gethosts (AF_INET6, struct in6_addr);
716 no_inet6_data = no_data;
718 else if (req->ai_family == AF_INET)
720 gethosts (AF_INET, struct in_addr);
721 no_inet6_data = no_data;
724 if (no_data != 0 && no_inet6_data != 0)
726 /* If both requests timed out report this. */
727 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
728 return -EAI_AGAIN;
730 /* We made requests but they turned out no data. The name
731 is known, though. */
732 return (GAIH_OKIFUNSPEC | -EAI_NODATA);
736 if (at->family == AF_UNSPEC)
737 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
739 else
741 struct gaih_addrtuple *atr;
742 atr = at = __alloca (sizeof (struct gaih_addrtuple));
743 memset (at, '\0', sizeof (struct gaih_addrtuple));
745 if (req->ai_family == 0)
747 at->next = __alloca (sizeof (struct gaih_addrtuple));
748 memset (at->next, '\0', sizeof (struct gaih_addrtuple));
751 if (req->ai_family == 0 || req->ai_family == AF_INET6)
753 at->family = AF_INET6;
754 if ((req->ai_flags & AI_PASSIVE) == 0)
755 memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
756 atr = at->next;
759 if (req->ai_family == 0 || req->ai_family == AF_INET)
761 atr->family = AF_INET;
762 if ((req->ai_flags & AI_PASSIVE) == 0)
763 *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
767 if (pai == NULL)
768 return 0;
771 struct gaih_servtuple *st2;
772 struct gaih_addrtuple *at2 = at;
773 size_t socklen, namelen;
774 sa_family_t family;
777 buffer is the size of an unformatted IPv6 address in printable format.
779 while (at2 != NULL)
781 const char *c = NULL;
783 /* Only the first entry gets the canonical name. */
784 if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
786 struct hostent *h = NULL;
788 int herrno;
789 struct hostent th;
790 size_t tmpbuflen = 512;
791 char *tmpbuf = NULL;
795 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2);
796 rc = __gethostbyaddr_r (at2->addr,
797 ((at2->family == AF_INET6)
798 ? sizeof(struct in6_addr)
799 : sizeof(struct in_addr)),
800 at2->family, &th, tmpbuf, tmpbuflen,
801 &h, &herrno);
804 while (rc == ERANGE && herrno == NETDB_INTERNAL);
806 if (rc != 0 && herrno == NETDB_INTERNAL)
808 __set_h_errno (herrno);
809 return -EAI_SYSTEM;
812 if (h != NULL)
813 c = h->h_name;
814 else
816 /* We have to try to get the canonical in some other
817 way. If we are looking for either AF_INET or
818 AF_INET6 try the other line. */
819 if (req->ai_family == AF_UNSPEC)
821 struct addrinfo *p = NULL;
822 struct addrinfo **end = &p;
823 struct addrinfo localreq = *req;
824 struct addrinfo *runp;
826 localreq.ai_family = AF_INET + AF_INET6 - at2->family;
827 (void) gaih_inet (name, service, &localreq, end);
829 runp = p;
830 while (runp != NULL)
832 if (p->ai_canonname != name)
834 c = strdupa (p->ai_canonname);
835 break;
837 runp = runp->ai_next;
840 freeaddrinfo (p);
843 /* If this code is used the missing canonical name is
844 substituted with the name passed in by the user. */
845 if (c == NULL)
846 c = name;
849 if (c == NULL)
850 return GAIH_OKIFUNSPEC | -EAI_NONAME;
852 #ifdef HAVE_LIBIDN
853 if (req->ai_flags & AI_CANONIDN)
855 int idn_flags = 0;
856 if (req->ai_flags & AI_IDN_ALLOW_UNASSIGNED)
857 idn_flags |= IDNA_ALLOW_UNASSIGNED;
858 if (req->ai_flags & AI_IDN_USE_STD3_ASCII_RULES)
859 idn_flags |= IDNA_USE_STD3_ASCII_RULES;
861 char *out;
862 int rc = __idna_to_unicode_lzlz (c, &out, idn_flags);
863 if (rc != IDNA_SUCCESS)
865 if (rc == IDNA_MALLOC_ERROR)
866 return -EAI_MEMORY;
867 if (rc == IDNA_DLOPEN_ERROR)
868 return -EAI_SYSTEM;
869 return -EAI_IDN_ENCODE;
871 /* In case the output string is the same as the input
872 string no new string has been allocated. */
873 if (out != c)
875 c = strdupa (out);
876 free (out);
879 #endif
881 namelen = strlen (c) + 1;
883 else
884 namelen = 0;
886 if (at2->family == AF_INET6)
888 family = AF_INET6;
889 socklen = sizeof (struct sockaddr_in6);
891 /* If we looked up IPv4 mapped address discard them here if
892 the caller isn't interested in all address and we have
893 found at least one IPv6 address. */
894 if (! got_ipv6
895 && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
896 && IN6_IS_ADDR_V4MAPPED (at2->addr))
897 goto ignore;
899 else
901 family = AF_INET;
902 socklen = sizeof (struct sockaddr_in);
905 for (st2 = st; st2 != NULL; st2 = st2->next)
907 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
908 if (*pai == NULL)
909 return -EAI_MEMORY;
911 (*pai)->ai_flags = req->ai_flags;
912 (*pai)->ai_family = family;
913 (*pai)->ai_socktype = st2->socktype;
914 (*pai)->ai_protocol = st2->protocol;
915 (*pai)->ai_addrlen = socklen;
916 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
917 #if SALEN
918 (*pai)->ai_addr->sa_len = socklen;
919 #endif /* SALEN */
920 (*pai)->ai_addr->sa_family = family;
922 if (family == AF_INET6)
924 struct sockaddr_in6 *sin6p =
925 (struct sockaddr_in6 *) (*pai)->ai_addr;
927 sin6p->sin6_flowinfo = 0;
928 memcpy (&sin6p->sin6_addr,
929 at2->addr, sizeof (struct in6_addr));
930 sin6p->sin6_port = st2->port;
931 sin6p->sin6_scope_id = at2->scopeid;
933 else
935 struct sockaddr_in *sinp =
936 (struct sockaddr_in *) (*pai)->ai_addr;
937 memcpy (&sinp->sin_addr,
938 at2->addr, sizeof (struct in_addr));
939 sinp->sin_port = st2->port;
940 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
943 if (namelen != 0)
945 (*pai)->ai_canonname = ((void *) (*pai) +
946 sizeof (struct addrinfo) + socklen);
947 strcpy ((*pai)->ai_canonname, c);
949 /* We do not need to allocate the canonical name anymore. */
950 namelen = 0;
952 else
953 (*pai)->ai_canonname = NULL;
955 (*pai)->ai_next = NULL;
956 pai = &((*pai)->ai_next);
959 ignore:
960 at2 = at2->next;
963 return 0;
966 static struct gaih gaih[] =
968 { PF_INET6, gaih_inet },
969 { PF_INET, gaih_inet },
970 #if 0
971 { PF_LOCAL, gaih_local },
972 #endif
973 { PF_UNSPEC, NULL }
976 struct sort_result
978 struct addrinfo *dest_addr;
979 struct sockaddr_storage source_addr;
980 bool got_source_addr;
984 static int
985 get_scope (const struct sockaddr_storage *ss)
987 int scope;
988 if (ss->ss_family == PF_INET6)
990 const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *) ss;
992 if (! IN6_IS_ADDR_MULTICAST (&in6->sin6_addr))
994 if (IN6_IS_ADDR_LINKLOCAL (&in6->sin6_addr))
995 scope = 2;
996 else if (IN6_IS_ADDR_SITELOCAL (&in6->sin6_addr))
997 scope = 5;
998 else
999 /* XXX Is this the correct default behavior? */
1000 scope = 14;
1002 else
1003 scope = in6->sin6_addr.s6_addr[1] & 0xf;
1005 else if (ss->ss_family == PF_INET)
1007 const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
1008 const uint8_t *addr = (const uint8_t *) &in->sin_addr;
1010 /* RFC 3484 specifies how to map IPv6 addresses to scopes.
1011 169.254/16 and 127/8 are link-local. */
1012 if ((addr[0] == 169 && addr[1] == 254) || addr[0] == 127)
1013 scope = 2;
1014 else if (addr[0] == 10 || (addr[0] == 172 && addr[1] == 16)
1015 || (addr[0] == 192 && addr[1] == 168))
1016 scope = 5;
1017 else
1018 scope = 14;
1020 else
1021 /* XXX What is a good default? */
1022 scope = 15;
1024 return scope;
1028 /* XXX The system administrator should be able to install other
1029 tables. We need to make this configurable. The problem is that
1030 the kernel is also involved since it needs the same table. */
1031 static const struct prefixlist
1033 struct in6_addr prefix;
1034 unsigned int bits;
1035 int val;
1036 } default_labels[] =
1038 /* See RFC 3484 for the details. */
1039 { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1040 0x0000, 0x0000, 0x0000, 0x0001 } } },
1041 128, 0 },
1042 { { .in6_u = { .u6_addr16 = { 0x2002, 0x0000, 0x0000, 0x0000,
1043 0x0000, 0x0000, 0x0000, 0x0000 } } },
1044 16, 2 },
1045 { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1046 0x0000, 0x0000, 0x0000, 0x0000 } } },
1047 96, 3 },
1048 { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1049 0x0000, 0xffff, 0x0000, 0x0000 } } },
1050 96, 4 },
1051 { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1052 0x0000, 0x0000, 0x0000, 0x0000 } } },
1053 0, 1 }
1057 static const struct prefixlist default_precedence[] =
1059 /* See RFC 3484 for the details. */
1060 { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1061 0x0000, 0x0000, 0x0000, 0x0001 } } },
1062 128, 50 },
1063 { { .in6_u = { .u6_addr16 = { 0x2002, 0x0000, 0x0000, 0x0000,
1064 0x0000, 0x0000, 0x0000, 0x0000 } } },
1065 16, 30 },
1066 { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1067 0x0000, 0x0000, 0x0000, 0x0000 } } },
1068 96, 20 },
1069 { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1070 0x0000, 0xffff, 0x0000, 0x0000 } } },
1071 96, 10 },
1072 { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1073 0x0000, 0x0000, 0x0000, 0x0000 } } },
1074 0, 40 }
1078 static int
1079 match_prefix (const struct sockaddr_storage *ss, const struct prefixlist *list,
1080 int default_val)
1082 int idx;
1083 struct sockaddr_in6 in6_mem;
1084 const struct sockaddr_in6 *in6;
1086 if (ss->ss_family == PF_INET6)
1087 in6 = (const struct sockaddr_in6 *) ss;
1088 else if (ss->ss_family == PF_INET)
1090 const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
1092 /* Convert to IPv6 address. */
1093 in6_mem.sin6_family = PF_INET6;
1094 in6_mem.sin6_port = in->sin_port;
1095 in6_mem.sin6_flowinfo = 0;
1096 if (in->sin_addr.s_addr == htonl (0x7f000001))
1097 in6_mem.sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
1098 else
1100 /* Construct a V4-to-6 mapped address. */
1101 memset (&in6_mem.sin6_addr, '\0', sizeof (in6_mem.sin6_addr));
1102 in6_mem.sin6_addr.s6_addr16[5] = 0xffff;
1103 in6_mem.sin6_addr.s6_addr32[3] = in->sin_addr.s_addr;
1104 in6_mem.sin6_scope_id = 0;
1107 in6 = &in6_mem;
1109 else
1110 return default_val;
1112 for (idx = 0; ; ++idx)
1114 unsigned int bits = list[idx].bits;
1115 uint8_t *mask = list[idx].prefix.s6_addr;
1116 uint8_t *val = in6->sin6_addr.s6_addr;
1118 while (bits > 8)
1120 if (*mask != *val)
1121 break;
1123 ++mask;
1124 ++val;
1125 bits -= 8;
1128 if (bits < 8)
1130 if ((*mask & (0xff00 >> bits)) == (*val & (0xff00 >> bits)))
1131 /* Match! */
1132 break;
1136 return list[idx].val;
1140 static int
1141 get_label (const struct sockaddr_storage *ss)
1143 /* XXX What is a good default value? */
1144 return match_prefix (ss, default_labels, INT_MAX);
1148 static int
1149 get_precedence (const struct sockaddr_storage *ss)
1151 /* XXX What is a good default value? */
1152 return match_prefix (ss, default_precedence, 0);
1156 static int
1157 rfc3484_sort (const void *p1, const void *p2)
1159 const struct sort_result *a1 = (const struct sort_result *) p1;
1160 const struct sort_result *a2 = (const struct sort_result *) p2;
1162 /* Rule 1: Avoid unusable destinations.
1163 We have the got_source_addr flag set if the destination is reachable. */
1164 if (a1->got_source_addr && ! a2->got_source_addr)
1165 return -1;
1166 if (! a1->got_source_addr && a2->got_source_addr)
1167 return 1;
1170 /* Rule 2: Prefer matching scope. Only interesting if both
1171 destination addresses are IPv6. */
1172 int a1_dst_scope
1173 = get_scope ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1175 int a2_dst_scope
1176 = get_scope ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1178 if (a1->got_source_addr)
1180 int a1_src_scope = get_scope (&a1->source_addr);
1181 int a2_src_scope = get_scope (&a2->source_addr);
1183 if (a1_dst_scope == a1_src_scope && a2_dst_scope != a2_src_scope)
1184 return -1;
1185 if (a1_dst_scope != a1_src_scope && a2_dst_scope == a2_src_scope)
1186 return 1;
1190 /* Rule 3: Avoid deprecated addresses.
1191 That's something only the kernel could decide. */
1193 /* Rule 4: Prefer home addresses.
1194 Another thing only the kernel can decide. */
1196 /* Rule 5: Prefer matching label. */
1197 if (a1->got_source_addr)
1199 int a1_dst_label
1200 = get_label ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1201 int a1_src_label = get_label (&a1->source_addr);
1203 int a2_dst_label
1204 = get_label ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1205 int a2_src_label = get_label (&a2->source_addr);
1207 if (a1_dst_label == a1_src_label && a2_dst_label != a2_src_label)
1208 return -1;
1209 if (a1_dst_label != a1_src_label && a2_dst_label == a2_src_label)
1210 return 1;
1214 /* Rule 6: Prefer higher precedence. */
1215 int a1_prec
1216 = get_precedence ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1217 int a2_prec
1218 = get_precedence ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1220 if (a1_prec > a2_prec)
1221 return -1;
1222 if (a1_prec < a2_prec)
1223 return 1;
1226 /* Rule 7: Prefer native transport.
1227 XXX How to recognize tunnels? */
1230 /* Rule 8: Prefer smaller scope. */
1231 if (a1_dst_scope < a2_dst_scope)
1232 return -1;
1233 if (a1_dst_scope > a2_dst_scope)
1234 return 1;
1237 /* Rule 9: Use longest matching prefix. */
1238 if (a1->got_source_addr
1239 && a1->dest_addr->ai_family == a2->dest_addr->ai_family)
1241 int bit1 = 0;
1242 int bit2 = 0;
1244 if (a1->dest_addr->ai_family == PF_INET)
1246 assert (a1->source_addr.ss_family == PF_INET);
1247 assert (a2->source_addr.ss_family == PF_INET);
1249 struct sockaddr_in *in1_dst;
1250 struct sockaddr_in *in1_src;
1251 struct sockaddr_in *in2_dst;
1252 struct sockaddr_in *in2_src;
1254 in1_dst = (struct sockaddr_in *) a1->dest_addr->ai_addr;
1255 in1_src = (struct sockaddr_in *) &a1->source_addr;
1256 in2_dst = (struct sockaddr_in *) a2->dest_addr->ai_addr;
1257 in2_src = (struct sockaddr_in *) &a2->source_addr;
1259 bit1 = ffs (in1_dst->sin_addr.s_addr ^ in1_src->sin_addr.s_addr);
1260 bit2 = ffs (in2_dst->sin_addr.s_addr ^ in2_src->sin_addr.s_addr);
1262 else if (a1->dest_addr->ai_family == PF_INET6)
1264 assert (a1->source_addr.ss_family == PF_INET6);
1265 assert (a2->source_addr.ss_family == PF_INET6);
1267 struct sockaddr_in6 *in1_dst;
1268 struct sockaddr_in6 *in1_src;
1269 struct sockaddr_in6 *in2_dst;
1270 struct sockaddr_in6 *in2_src;
1272 in1_dst = (struct sockaddr_in6 *) a1->dest_addr->ai_addr;
1273 in1_src = (struct sockaddr_in6 *) &a1->source_addr;
1274 in2_dst = (struct sockaddr_in6 *) a2->dest_addr->ai_addr;
1275 in2_src = (struct sockaddr_in6 *) &a2->source_addr;
1277 int i;
1278 for (i = 0; i < 4; ++i)
1279 if (in1_dst->sin6_addr.s6_addr32[i]
1280 != in1_src->sin6_addr.s6_addr32[i]
1281 || (in2_dst->sin6_addr.s6_addr32[i]
1282 != in2_src->sin6_addr.s6_addr32[i]))
1283 break;
1285 if (i < 4)
1287 bit1 = ffs (in1_dst->sin6_addr.s6_addr32[i]
1288 ^ in1_src->sin6_addr.s6_addr32[i]);
1289 bit2 = ffs (in2_dst->sin6_addr.s6_addr32[i]
1290 ^ in2_src->sin6_addr.s6_addr32[i]);
1294 if (bit1 > bit2)
1295 return -1;
1296 if (bit1 < bit2)
1297 return 1;
1301 /* Rule 10: Otherwise, leave the order unchanged. */
1302 return 0;
1307 getaddrinfo (const char *name, const char *service,
1308 const struct addrinfo *hints, struct addrinfo **pai)
1310 int i = 0, j = 0, last_i = 0;
1311 int nresults = 0;
1312 struct addrinfo *p = NULL, **end;
1313 struct gaih *g = gaih, *pg = NULL;
1314 struct gaih_service gaih_service, *pservice;
1315 struct addrinfo local_hints;
1317 if (name != NULL && name[0] == '*' && name[1] == 0)
1318 name = NULL;
1320 if (service != NULL && service[0] == '*' && service[1] == 0)
1321 service = NULL;
1323 if (name == NULL && service == NULL)
1324 return EAI_NONAME;
1326 if (hints == NULL)
1327 hints = &default_hints;
1329 if (hints->ai_flags
1330 & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|AI_ADDRCONFIG|AI_V4MAPPED
1331 #ifdef HAVE_LIBIDN
1332 |AI_IDN|AI_CANONIDN|AI_IDN_ALLOW_UNASSIGNED
1333 |AI_IDN_USE_STD3_ASCII_RULES
1334 #endif
1335 |AI_NUMERICSERV|AI_ALL))
1336 return EAI_BADFLAGS;
1338 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
1339 return EAI_BADFLAGS;
1341 if (hints->ai_flags & AI_ADDRCONFIG)
1343 /* Determine whether we have IPv4 or IPv6 interfaces or both.
1344 We cannot cache the results since new interfaces could be
1345 added at any time. */
1346 bool seen_ipv4;
1347 bool seen_ipv6;
1348 __check_pf (&seen_ipv4, &seen_ipv6);
1350 /* Now make a decision on what we return, if anything. */
1351 if (hints->ai_family == PF_UNSPEC && (seen_ipv4 || seen_ipv6))
1353 /* If we haven't seen both IPv4 and IPv6 interfaces we can
1354 narrow down the search. */
1355 if (! seen_ipv4 || ! seen_ipv6)
1357 local_hints = *hints;
1358 local_hints.ai_family = seen_ipv4 ? PF_INET : PF_INET6;
1359 hints = &local_hints;
1362 else if ((hints->ai_family == PF_INET && ! seen_ipv4)
1363 || (hints->ai_family == PF_INET6 && ! seen_ipv6))
1364 /* We cannot possibly return a valid answer. */
1365 return EAI_NONAME;
1368 if (service && service[0])
1370 char *c;
1371 gaih_service.name = service;
1372 gaih_service.num = strtoul (gaih_service.name, &c, 10);
1373 if (*c != '\0')
1375 if (hints->ai_flags & AI_NUMERICSERV)
1376 return EAI_NONAME;
1378 gaih_service.num = -1;
1380 else
1381 /* Can't specify a numerical socket unless a protocol family was
1382 given. */
1383 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
1384 return EAI_SERVICE;
1385 pservice = &gaih_service;
1387 else
1388 pservice = NULL;
1390 if (pai)
1391 end = &p;
1392 else
1393 end = NULL;
1395 while (g->gaih)
1397 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
1399 j++;
1400 if (pg == NULL || pg->gaih != g->gaih)
1402 pg = g;
1403 i = g->gaih (name, pservice, hints, end);
1404 if (i != 0)
1406 /* EAI_NODATA is a more specific result as it says that
1407 we found a result but it is not usable. */
1408 if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA))
1409 last_i = i;
1411 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
1413 ++g;
1414 continue;
1417 freeaddrinfo (p);
1419 return -(i & GAIH_EAI);
1421 if (end)
1422 while (*end)
1424 end = &((*end)->ai_next);
1425 ++nresults;
1429 ++g;
1432 if (j == 0)
1433 return EAI_FAMILY;
1435 if (nresults > 1)
1437 /* Sort results according to RFC 3484. */
1438 struct sort_result results[nresults];
1439 struct addrinfo *q;
1441 for (i = 0, q = p; q != NULL; ++i, q = q->ai_next)
1443 results[i].dest_addr = q;
1444 results[i].got_source_addr = false;
1446 /* We overwrite the type with SOCK_DGRAM since we do not
1447 want connect() to connect to the other side. If we
1448 cannot determine the source address remember this
1449 fact. */
1450 int fd = __socket (q->ai_family, SOCK_DGRAM, IPPROTO_IP);
1451 if (fd != -1)
1453 socklen_t sl = sizeof (results[i].source_addr);
1454 if (__connect (fd, q->ai_addr, q->ai_addrlen) == 0
1455 && __getsockname (fd,
1456 (struct sockaddr *) &results[i].source_addr,
1457 &sl) == 0)
1458 results[i].got_source_addr = true;
1460 close_not_cancel_no_status (fd);
1464 /* We got all the source addresses we can get, now sort using
1465 the information. */
1466 qsort (results, nresults, sizeof (results[0]), rfc3484_sort);
1468 /* Queue the results up as they come out of sorting. */
1469 q = p = results[0].dest_addr;
1470 for (i = 1; i < nresults; ++i)
1471 q = q->ai_next = results[i].dest_addr;
1472 q->ai_next = NULL;
1475 if (p)
1477 *pai = p;
1478 return 0;
1481 if (pai == NULL && last_i == 0)
1482 return 0;
1484 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
1486 libc_hidden_def (getaddrinfo)
1488 static_link_warning (getaddrinfo)
1490 void
1491 freeaddrinfo (struct addrinfo *ai)
1493 struct addrinfo *p;
1495 while (ai != NULL)
1497 p = ai;
1498 ai = ai->ai_next;
1499 free (p);
1502 libc_hidden_def (freeaddrinfo)