2b6f0ba0acff956735d5a22f281be0943522988a
[kopensolaris-gnu/glibc.git] / sysdeps / posix / getaddrinfo.c
1 /* The Inner Net License, Version 2.00
2
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:
6
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.
22
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.
33
34   If these license terms cause you a real problem, contact the author.  */
35
36 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved.  */
37
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>
57
58 extern int __idna_to_ascii_lz (const char *input, char **output, int flags);
59 #define IDNA_SUCCESS 0
60
61 #define GAIH_OKIFUNSPEC 0x0100
62 #define GAIH_EAI        ~(GAIH_OKIFUNSPEC)
63
64 #ifndef UNIX_PATH_MAX
65 #define UNIX_PATH_MAX  108
66 #endif
67
68 struct gaih_service
69   {
70     const char *name;
71     int num;
72   };
73
74 struct gaih_servtuple
75   {
76     struct gaih_servtuple *next;
77     int socktype;
78     int protocol;
79     int port;
80   };
81
82 static const struct gaih_servtuple nullserv;
83
84 struct gaih_addrtuple
85   {
86     struct gaih_addrtuple *next;
87     int family;
88     char addr[16];
89     uint32_t scopeid;
90   };
91
92 struct gaih_typeproto
93   {
94     int socktype;
95     int protocol;
96     char name[4];
97     int protoflag;
98   };
99
100 /* Values for `protoflag'.  */
101 #define GAI_PROTO_NOSERVICE     1
102 #define GAI_PROTO_PROTOANY      2
103
104 static const struct gaih_typeproto gaih_inet_typeproto[] =
105 {
106   { 0, 0, "", 0 },
107   { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
108   { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
109   { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
110   { 0, 0, "", 0 }
111 };
112
113 struct gaih
114   {
115     int family;
116     int (*gaih)(const char *name, const struct gaih_service *service,
117                 const struct addrinfo *req, struct addrinfo **pai);
118   };
119
120 static const struct addrinfo default_hints =
121   {
122     .ai_flags = AI_DEFAULT,
123     .ai_family = PF_UNSPEC,
124     .ai_socktype = 0,
125     .ai_protocol = 0,
126     .ai_addrlen = 0,
127     .ai_addr = NULL,
128     .ai_canonname = NULL,
129     .ai_next = NULL
130   };
131
132
133 #if 0
134 /* Using Unix sockets this way is a security risk.  */
135 static int
136 gaih_local (const char *name, const struct gaih_service *service,
137             const struct addrinfo *req, struct addrinfo **pai)
138 {
139   struct utsname utsname;
140
141   if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
142     return GAIH_OKIFUNSPEC | -EAI_NONAME;
143
144   if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
145     if (uname (&utsname) < 0)
146       return -EAI_SYSTEM;
147
148   if (name != NULL)
149     {
150       if (strcmp(name, "localhost") &&
151           strcmp(name, "local") &&
152           strcmp(name, "unix") &&
153           strcmp(name, utsname.nodename))
154         return GAIH_OKIFUNSPEC | -EAI_NONAME;
155     }
156
157   if (req->ai_protocol || req->ai_socktype)
158     {
159       const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
160
161       while (tp->name[0]
162              && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
163                  || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
164                  || (req->ai_protocol != 0
165                      && !(tp->protoflag & GAI_PROTO_PROTOANY)
166                      && req->ai_protocol != tp->protocol)))
167         ++tp;
168
169       if (! tp->name[0])
170         {
171           if (req->ai_socktype)
172             return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
173           else
174             return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
175         }
176     }
177
178   *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
179                  + ((req->ai_flags & AI_CANONNAME)
180                     ? (strlen(utsname.nodename) + 1): 0));
181   if (*pai == NULL)
182     return -EAI_MEMORY;
183
184   (*pai)->ai_next = NULL;
185   (*pai)->ai_flags = req->ai_flags;
186   (*pai)->ai_family = AF_LOCAL;
187   (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
188   (*pai)->ai_protocol = req->ai_protocol;
189   (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
190   (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
191
192 #if SALEN
193   ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
194     sizeof (struct sockaddr_un);
195 #endif /* SALEN */
196
197   ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
198   memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
199
200   if (service)
201     {
202       struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
203
204       if (strchr (service->name, '/') != NULL)
205         {
206           if (strlen (service->name) >= sizeof (sunp->sun_path))
207             return GAIH_OKIFUNSPEC | -EAI_SERVICE;
208
209           strcpy (sunp->sun_path, service->name);
210         }
211       else
212         {
213           if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
214               sizeof (sunp->sun_path))
215             return GAIH_OKIFUNSPEC | -EAI_SERVICE;
216
217           __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
218         }
219     }
220   else
221     {
222       /* This is a dangerous use of the interface since there is a time
223          window between the test for the file and the actual creation
224          (done by the caller) in which a file with the same name could
225          be created.  */
226       char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
227
228       if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
229                             0) != 0
230           || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
231         return -EAI_SYSTEM;
232     }
233
234   if (req->ai_flags & AI_CANONNAME)
235     (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
236                                    + sizeof (struct sockaddr_un),
237                                    utsname.nodename);
238   else
239     (*pai)->ai_canonname = NULL;
240   return 0;
241 }
242 #endif  /* 0 */
243
244 static int
245 gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
246                const struct addrinfo *req, struct gaih_servtuple *st)
247 {
248   struct servent *s;
249   size_t tmpbuflen = 1024;
250   struct servent ts;
251   char *tmpbuf;
252   int r;
253
254   do
255     {
256       tmpbuf = __alloca (tmpbuflen);
257
258       r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
259                              &s);
260       if (r != 0 || s == NULL)
261         {
262           if (r == ERANGE)
263             tmpbuflen *= 2;
264           else
265             return GAIH_OKIFUNSPEC | -EAI_SERVICE;
266         }
267     }
268   while (r);
269
270   st->next = NULL;
271   st->socktype = tp->socktype;
272   st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
273                   ? req->ai_protocol : tp->protocol);
274   st->port = s->s_port;
275
276   return 0;
277 }
278
279 #define gethosts(_family, _type) \
280  {                                                                            \
281   int i, herrno;                                                              \
282   size_t tmpbuflen;                                                           \
283   struct hostent th;                                                          \
284   char *tmpbuf = NULL;                                                        \
285   tmpbuflen = 512;                                                            \
286   no_data = 0;                                                                \
287   do {                                                                        \
288     tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);                \
289     rc = __gethostbyname2_r (name, _family, &th, tmpbuf,                      \
290          tmpbuflen, &h, &herrno);                                             \
291   } while (rc == ERANGE && herrno == NETDB_INTERNAL);                         \
292   if (rc != 0)                                                                \
293     {                                                                         \
294       if (herrno == NETDB_INTERNAL)                                           \
295         {                                                                     \
296           __set_h_errno (herrno);                                             \
297           return -EAI_SYSTEM;                                                 \
298         }                                                                     \
299       if (herrno == TRY_AGAIN)                                                \
300         no_data = EAI_AGAIN;                                                  \
301       else                                                                    \
302         no_data = herrno == NO_DATA;                                          \
303     }                                                                         \
304   else if (h != NULL)                                                         \
305     {                                                                         \
306       for (i = 0; h->h_addr_list[i]; i++)                                     \
307         {                                                                     \
308           if (*pat == NULL) {                                                 \
309             *pat = __alloca (sizeof (struct gaih_addrtuple));                 \
310             (*pat)->scopeid = 0;                                              \
311           }                                                                   \
312           (*pat)->next = NULL;                                                \
313           (*pat)->family = _family;                                           \
314           memcpy ((*pat)->addr, h->h_addr_list[i],                            \
315                  sizeof(_type));                                              \
316           pat = &((*pat)->next);                                              \
317         }                                                                     \
318       if (_family == AF_INET6)                                                \
319         got_ipv6 = true;                                                      \
320     }                                                                         \
321   else if (_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))              \
322     {                                                                         \
323       /* We have to add V4 mapped addresses.  Maybe we discard them           \
324          later again but we get them anyhow for now.  */                      \
325       while ((rc = __gethostbyname2_r (name, AF_INET6, &th, tmpbuf,           \
326                                        tmpbuflen, &h, &herrno)) == ERANGE     \
327              && herrno == NETDB_INTERNAL)                                     \
328         tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);            \
329                                                                               \
330       if (rc != 0)                                                            \
331         {                                                                     \
332           if (herrno == NETDB_INTERNAL)                                       \
333             {                                                                 \
334               __set_h_errno (herrno);                                         \
335               return -EAI_SYSTEM;                                             \
336             }                                                                 \
337           if (herrno == TRY_AGAIN)                                            \
338             no_data = EAI_AGAIN;                                              \
339           else                                                                \
340             no_data = herrno == NO_DATA;                                      \
341         }                                                                     \
342       else if (h != NULL)                                                     \
343         {                                                                     \
344           for (i = 0; h->h_addr_list[i]; ++i)                                 \
345             {                                                                 \
346               if (*pat == NULL)                                               \
347                 {                                                             \
348                   *pat = __alloca (sizeof (struct gaih_addrtuple));           \
349                   (*pat)->scopeid = 0;                                        \
350                 }                                                             \
351               uint32_t *addr = (uint32_t *) (*pat)->addr;                     \
352               (*pat)->next = NULL;                                            \
353               (*pat)->family = _family;                                       \
354               addr[3] = *(uint32_t *) h->h_addr_list[i];                      \
355               addr[2] = htonl (0xffff);                                       \
356               addr[1] = 0;                                                    \
357               addr[0] = 0;                                                    \
358               pat = &((*pat)->next);                                          \
359             }                                                                 \
360         }                                                                     \
361     }                                                                         \
362  }
363
364
365 #define gethosts2(_family, _type) \
366  {                                                                            \
367   int i, herrno;                                                              \
368   size_t tmpbuflen;                                                           \
369   struct hostent th;                                                          \
370   char *tmpbuf = NULL;                                                        \
371   tmpbuflen = 512;                                                            \
372   no_data = 0;                                                                \
373   do {                                                                        \
374     tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);                \
375     rc = 0;                                                                   \
376     status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf,                   \
377            tmpbuflen, &rc, &herrno));                                         \
378   } while (rc == ERANGE && herrno == NETDB_INTERNAL);                         \
379   if (status == NSS_STATUS_SUCCESS && rc == 0)                                \
380     h = &th;                                                                  \
381   else                                                                        \
382     h = NULL;                                                                 \
383   if (rc != 0)                                                                \
384     {                                                                         \
385       if (herrno == NETDB_INTERNAL)                                           \
386         {                                                                     \
387           __set_h_errno (herrno);                                             \
388           return -EAI_SYSTEM;                                                 \
389         }                                                                     \
390       if (herrno == TRY_AGAIN)                                                \
391         no_data = EAI_AGAIN;                                                  \
392       else                                                                    \
393         no_data = herrno == NO_DATA;                                          \
394     }                                                                         \
395   else if (h != NULL)                                                         \
396     {                                                                         \
397       for (i = 0; h->h_addr_list[i]; i++)                                     \
398         {                                                                     \
399           if (*pat == NULL) {                                                 \
400             *pat = __alloca (sizeof (struct gaih_addrtuple));                 \
401             (*pat)->scopeid = 0;                                              \
402           }                                                                   \
403           (*pat)->next = NULL;                                                \
404           (*pat)->family = _family;                                           \
405           memcpy ((*pat)->addr, h->h_addr_list[i],                            \
406                  sizeof(_type));                                              \
407           pat = &((*pat)->next);                                              \
408         }                                                                     \
409     }                                                                         \
410  }
411
412 typedef enum nss_status (*nss_gethostbyname2_r)
413   (const char *name, int af, struct hostent *host,
414    char *buffer, size_t buflen, int *errnop,
415    int *h_errnop);
416 extern service_user *__nss_hosts_database attribute_hidden;
417
418 static int
419 gaih_inet (const char *name, const struct gaih_service *service,
420            const struct addrinfo *req, struct addrinfo **pai)
421 {
422   const struct gaih_typeproto *tp = gaih_inet_typeproto;
423   struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
424   struct gaih_addrtuple *at = NULL;
425   int rc;
426   bool got_ipv6 = false;
427
428   if (req->ai_protocol || req->ai_socktype)
429     {
430       ++tp;
431
432       while (tp->name[0]
433              && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
434                  || (req->ai_protocol != 0
435                      && !(tp->protoflag & GAI_PROTO_PROTOANY)
436                      && req->ai_protocol != tp->protocol)))
437         ++tp;
438
439       if (! tp->name[0])
440         {
441           if (req->ai_socktype)
442             return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
443           else
444             return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
445         }
446     }
447
448   if (service != NULL)
449     {
450       if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
451         return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
452
453       if (service->num < 0)
454         {
455           if (tp->name[0])
456             {
457               st = (struct gaih_servtuple *)
458                 __alloca (sizeof (struct gaih_servtuple));
459
460               if ((rc = gaih_inet_serv (service->name, tp, req, st)))
461                 return rc;
462             }
463           else
464             {
465               struct gaih_servtuple **pst = &st;
466               for (tp++; tp->name[0]; tp++)
467                 {
468                   struct gaih_servtuple *newp;
469
470                   if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
471                     continue;
472
473                   if (req->ai_socktype != 0
474                       && req->ai_socktype != tp->socktype)
475                     continue;
476                   if (req->ai_protocol != 0
477                       && !(tp->protoflag & GAI_PROTO_PROTOANY)
478                       && req->ai_protocol != tp->protocol)
479                     continue;
480
481                   newp = (struct gaih_servtuple *)
482                     __alloca (sizeof (struct gaih_servtuple));
483
484                   if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
485                     {
486                       if (rc & GAIH_OKIFUNSPEC)
487                         continue;
488                       return rc;
489                     }
490
491                   *pst = newp;
492                   pst = &(newp->next);
493                 }
494               if (st == (struct gaih_servtuple *) &nullserv)
495                 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
496             }
497         }
498       else
499         {
500           st = __alloca (sizeof (struct gaih_servtuple));
501           st->next = NULL;
502           st->socktype = tp->socktype;
503           st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
504                           ? req->ai_protocol : tp->protocol);
505           st->port = htons (service->num);
506         }
507     }
508   else if (req->ai_socktype || req->ai_protocol)
509     {
510       st = __alloca (sizeof (struct gaih_servtuple));
511       st->next = NULL;
512       st->socktype = tp->socktype;
513       st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
514                       ? req->ai_protocol : tp->protocol);
515       st->port = 0;
516     }
517   else
518     {
519       /* Neither socket type nor protocol is set.  Return all socket types
520          we know about.  */
521       struct gaih_servtuple **lastp = &st;
522       for (++tp; tp->name[0]; ++tp)
523         {
524           struct gaih_servtuple *newp;
525
526           newp = __alloca (sizeof (struct gaih_servtuple));
527           newp->next = NULL;
528           newp->socktype = tp->socktype;
529           newp->protocol = tp->protocol;
530           newp->port = 0;
531
532           *lastp = newp;
533           lastp = &newp->next;
534         }
535     }
536
537   if (name != NULL)
538     {
539       at = __alloca (sizeof (struct gaih_addrtuple));
540
541       at->family = AF_UNSPEC;
542       at->scopeid = 0;
543       at->next = NULL;
544
545 #ifdef HAVE_LIBIDN
546       if (req->ai_flags & AI_IDN)
547         {
548           char *p = NULL;
549           rc = __idna_to_ascii_lz (name, &p, 0);
550           if (rc != IDNA_SUCCESS)
551             return -EAI_IDN_ENCODE;
552           name = strdupa (p);
553           free (p);
554         }
555 #endif
556
557       if (inet_pton (AF_INET, name, at->addr) > 0)
558         {
559           if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
560             at->family = AF_INET;
561           else if (req->ai_flags & AI_V4MAPPED)
562             {
563               ((uint32_t *) at->addr)[3] = *(uint32_t *) at->addr;
564               ((uint32_t *) at->addr)[2] = htonl (0xffff);
565               ((uint32_t *) at->addr)[1] = 0;
566               ((uint32_t *) at->addr)[0] = 0;
567             }
568           else
569             return -EAI_ADDRFAMILY;
570         }
571
572       if (at->family == AF_UNSPEC)
573         {
574           char *namebuf = strdupa (name);
575           char *scope_delim;
576
577           scope_delim = strchr (namebuf, SCOPE_DELIMITER);
578           if (scope_delim != NULL)
579             *scope_delim = '\0';
580
581           if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
582             {
583               if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
584                 at->family = AF_INET6;
585               else if (IN6_IS_ADDR_V4MAPPED (at->addr))
586                 *(uint32_t *) at->addr = ((uint32_t *) at->addr)[3];
587               else
588                 return -EAI_ADDRFAMILY;
589
590               if (scope_delim != NULL)
591                 {
592                   int try_numericscope = 0;
593                   if (IN6_IS_ADDR_LINKLOCAL (at->addr)
594                       || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
595                     {
596                       at->scopeid = if_nametoindex (scope_delim + 1);
597                       if (at->scopeid == 0)
598                         try_numericscope = 1;
599                     }
600                   else
601                     try_numericscope = 1;
602
603                   if (try_numericscope != 0)
604                     {
605                       char *end;
606                       assert (sizeof (uint32_t) <= sizeof (unsigned long));
607                       at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
608                                                         10);
609                       if (*end != '\0')
610                         return GAIH_OKIFUNSPEC | -EAI_NONAME;
611                     }
612                 }
613             }
614         }
615
616       if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
617         {
618           struct hostent *h;
619           struct gaih_addrtuple **pat = &at;
620           int no_data = 0;
621           int no_inet6_data = 0;
622           /* If we are looking for both IPv4 and IPv6 address we don't
623              want the lookup functions to automatically promote IPv4
624              addresses to IPv6 addresses.  Currently this is decided
625              by setting the RES_USE_INET6 bit in _res.options.  */
626           if (req->ai_family == AF_UNSPEC)
627             {
628               service_user *nip = NULL;
629               enum nss_status inet6_status, status = NSS_STATUS_UNAVAIL;
630               int no_more;
631               nss_gethostbyname2_r fct;
632               int old_res_options;
633
634               if (__nss_hosts_database != NULL)
635                 {
636                   no_more = 0;
637                   nip = __nss_hosts_database;
638                 }
639               else
640                 no_more = __nss_database_lookup ("hosts", NULL,
641                                                  "dns [!UNAVAIL=return] files", &nip);
642
643               if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1)
644                 no_more = 1;
645               old_res_options = _res.options;
646               _res.options &= ~RES_USE_INET6;
647
648               while (!no_more)
649                 {
650                   fct = __nss_lookup_function (nip, "gethostbyname2_r");
651
652                   if (fct != NULL)
653                     {
654                       gethosts2 (AF_INET6, struct in6_addr);
655                       no_inet6_data = no_data;
656                       inet6_status = status;
657                       gethosts2 (AF_INET, struct in_addr);
658
659                       /* If we found one address for AF_INET or AF_INET6,
660                          don't continue the search.  */
661                       if (inet6_status == NSS_STATUS_SUCCESS ||
662                           status == NSS_STATUS_SUCCESS)
663                         break;
664
665                       /* We can have different states for AF_INET
666                          and AF_INET6. Try to find a usefull one for
667                          both.  */
668                       if (inet6_status == NSS_STATUS_TRYAGAIN)
669                         status = NSS_STATUS_TRYAGAIN;
670                       else if (status == NSS_STATUS_UNAVAIL &&
671                                inet6_status != NSS_STATUS_UNAVAIL)
672                         status = inet6_status;
673                     }
674
675                   if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
676                     break;
677
678                   if (nip->next == NULL)
679                     no_more = -1;
680                   else
681                     nip = nip->next;
682                 }
683
684               _res.options = old_res_options;
685             }
686           else if (req->ai_family == AF_INET6)
687             {
688               gethosts (AF_INET6, struct in6_addr);
689               no_inet6_data = no_data;
690             }
691           else if (req->ai_family == AF_INET)
692             {
693               gethosts (AF_INET, struct in_addr);
694               no_inet6_data = no_data;
695             }
696
697           if (no_data != 0 && no_inet6_data != 0)
698             {
699               /* If both requests timed out report this.  */
700               if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
701                 return -EAI_AGAIN;
702
703               /* We made requests but they turned out no data.  The name
704                  is known, though.  */
705               return (GAIH_OKIFUNSPEC | -EAI_NODATA);
706             }
707         }
708
709       if (at->family == AF_UNSPEC)
710         return (GAIH_OKIFUNSPEC | -EAI_NONAME);
711     }
712   else
713     {
714       struct gaih_addrtuple *atr;
715       atr = at = __alloca (sizeof (struct gaih_addrtuple));
716       memset (at, '\0', sizeof (struct gaih_addrtuple));
717
718       if (req->ai_family == 0)
719         {
720           at->next = __alloca (sizeof (struct gaih_addrtuple));
721           memset (at->next, '\0', sizeof (struct gaih_addrtuple));
722         }
723
724       if (req->ai_family == 0 || req->ai_family == AF_INET6)
725         {
726           at->family = AF_INET6;
727           if ((req->ai_flags & AI_PASSIVE) == 0)
728             memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
729           atr = at->next;
730         }
731
732       if (req->ai_family == 0 || req->ai_family == AF_INET)
733         {
734           atr->family = AF_INET;
735           if ((req->ai_flags & AI_PASSIVE) == 0)
736             *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
737         }
738     }
739
740   if (pai == NULL)
741     return 0;
742
743   {
744     const char *c = NULL;
745     struct gaih_servtuple *st2;
746     struct gaih_addrtuple *at2 = at;
747     size_t socklen, namelen;
748     sa_family_t family;
749
750     /*
751       buffer is the size of an unformatted IPv6 address in printable format.
752      */
753     while (at2 != NULL)
754       {
755         if (req->ai_flags & AI_CANONNAME)
756           {
757             struct hostent *h = NULL;
758
759             int herrno;
760             struct hostent th;
761             size_t tmpbuflen = 512;
762             char *tmpbuf = NULL;
763
764             do
765               {
766                 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2);
767                 rc = __gethostbyaddr_r (at2->addr,
768                                         ((at2->family == AF_INET6)
769                                          ? sizeof(struct in6_addr)
770                                          : sizeof(struct in_addr)),
771                                         at2->family, &th, tmpbuf, tmpbuflen,
772                                         &h, &herrno);
773
774               }
775             while (rc == ERANGE && herrno == NETDB_INTERNAL);
776
777             if (rc != 0 && herrno == NETDB_INTERNAL)
778               {
779                 __set_h_errno (herrno);
780                 return -EAI_SYSTEM;
781               }
782
783             if (h != NULL)
784               c = h->h_name;
785             else
786               {
787                 /* We have to try to get the canonical in some other
788                    way.  If we are looking for either AF_INET or
789                    AF_INET6 try the other line.  */
790                 if (req->ai_family == AF_UNSPEC)
791                   {
792                     struct addrinfo *p = NULL;
793                     struct addrinfo **end = &p;
794                     struct addrinfo localreq = *req;
795                     struct addrinfo *runp;
796
797                     localreq.ai_family = AF_INET + AF_INET6 - at2->family;
798                     (void) gaih_inet (name, service, &localreq, end);
799
800                     runp = p;
801                     while (runp != NULL)
802                       {
803                         if (p->ai_canonname != name)
804                           {
805                             c = strdupa (p->ai_canonname);
806                             break;
807                           }
808                         runp = runp->ai_next;
809                       }
810
811                     freeaddrinfo (p);
812                   }
813
814                 /* If this code is used the missing canonical name is
815                    substituted with the name passed in by the user.  */
816                 if (c == NULL)
817                   c = name;
818               }
819
820             if (c == NULL)
821               return GAIH_OKIFUNSPEC | -EAI_NONAME;
822
823             namelen = strlen (c) + 1;
824           }
825         else
826           namelen = 0;
827
828         if (at2->family == AF_INET6)
829           {
830             family = AF_INET6;
831             socklen = sizeof (struct sockaddr_in6);
832
833             /* If we looked up IPv4 mapped address discard them here if
834                the caller isn't interested in all address and we have
835                found at least one IPv6 address.  */
836             if (! got_ipv6
837                 && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
838                 && IN6_IS_ADDR_V4MAPPED (at2->addr))
839               goto ignore;
840           }
841         else
842           {
843             family = AF_INET;
844             socklen = sizeof (struct sockaddr_in);
845           }
846
847         for (st2 = st; st2 != NULL; st2 = st2->next)
848           {
849             *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
850             if (*pai == NULL)
851               return -EAI_MEMORY;
852
853             (*pai)->ai_flags = req->ai_flags;
854             (*pai)->ai_family = family;
855             (*pai)->ai_socktype = st2->socktype;
856             (*pai)->ai_protocol = st2->protocol;
857             (*pai)->ai_addrlen = socklen;
858             (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
859 #if SALEN
860             (*pai)->ai_addr->sa_len = socklen;
861 #endif /* SALEN */
862             (*pai)->ai_addr->sa_family = family;
863
864             if (family == AF_INET6)
865               {
866                 struct sockaddr_in6 *sin6p =
867                   (struct sockaddr_in6 *) (*pai)->ai_addr;
868
869                 sin6p->sin6_flowinfo = 0;
870                 memcpy (&sin6p->sin6_addr,
871                         at2->addr, sizeof (struct in6_addr));
872                 sin6p->sin6_port = st2->port;
873                 sin6p->sin6_scope_id = at2->scopeid;
874               }
875             else
876               {
877                 struct sockaddr_in *sinp =
878                   (struct sockaddr_in *) (*pai)->ai_addr;
879                 memcpy (&sinp->sin_addr,
880                         at2->addr, sizeof (struct in_addr));
881                 sinp->sin_port = st2->port;
882                 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
883               }
884
885             if (c)
886               {
887                 (*pai)->ai_canonname = ((void *) (*pai) +
888                                         sizeof (struct addrinfo) + socklen);
889                 strcpy ((*pai)->ai_canonname, c);
890               }
891             else
892               (*pai)->ai_canonname = NULL;
893
894             (*pai)->ai_next = NULL;
895             pai = &((*pai)->ai_next);
896           }
897
898       ignore:
899         at2 = at2->next;
900       }
901   }
902   return 0;
903 }
904
905 static struct gaih gaih[] =
906   {
907     { PF_INET6, gaih_inet },
908     { PF_INET, gaih_inet },
909 #if 0
910     { PF_LOCAL, gaih_local },
911 #endif
912     { PF_UNSPEC, NULL }
913   };
914
915 struct sort_result
916 {
917   struct addrinfo *dest_addr;
918   struct sockaddr_storage source_addr;
919   bool got_source_addr;
920 };
921
922
923 static int
924 get_scope (const struct sockaddr_storage *ss)
925 {
926   int scope;
927   if (ss->ss_family == PF_INET6)
928     {
929       const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *) ss;
930
931       if (! IN6_IS_ADDR_MULTICAST (&in6->sin6_addr))
932         {
933           if (IN6_IS_ADDR_LINKLOCAL (&in6->sin6_addr))
934             scope = 2;
935           else if (IN6_IS_ADDR_SITELOCAL (&in6->sin6_addr))
936             scope = 5;
937           else
938             /* XXX Is this the correct default behavior?  */
939             scope = 14;
940         }
941       else
942         scope = in6->sin6_addr.s6_addr[1] & 0xf;
943     }
944   else if (ss->ss_family == PF_INET)
945     {
946       const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
947       const uint8_t *addr = (const uint8_t *) &in->sin_addr;
948
949       /* RFC 3484 specifies how to map IPv6 addresses to scopes.
950          169.254/16 and 127/8 are link-local.  */
951       if ((addr[0] == 169 && addr[1] == 254) || addr[0] == 127)
952         scope = 2;
953       else if (addr[0] == 10 || (addr[0] == 172 && addr[1] == 16)
954                || (addr[0] == 192 && addr[1] == 168))
955         scope = 5;
956       else
957         scope = 14;
958     }
959   else
960     /* XXX What is a good default?  */
961     scope = 15;
962
963   return scope;
964 }
965
966
967 /* XXX The system administrator should be able to install other
968    tables.  We need to make this configurable.  The problem is that
969    the kernel is also involved since it needs the same table.  */
970 static const struct prefixlist
971 {
972   struct in6_addr prefix;
973   unsigned int bits;
974   int val;
975 } default_labels[] =
976   {
977     /* See RFC 3484 for the details.  */
978     { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
979                                   0x0000, 0x0000, 0x0000, 0x0001 } } },
980       128, 0 },
981     { { .in6_u = { .u6_addr16 = { 0x2002, 0x0000, 0x0000, 0x0000,
982                                   0x0000, 0x0000, 0x0000, 0x0000 } } },
983       16, 2 },
984     { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
985                                   0x0000, 0x0000, 0x0000, 0x0000 } } },
986       96, 3 },
987     { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
988                                   0x0000, 0xffff, 0x0000, 0x0000 } } },
989       96, 4 },
990     { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
991                                   0x0000, 0x0000, 0x0000, 0x0000 } } },
992       0, 1 }
993   };
994
995
996 static const struct prefixlist default_precedence[] =
997   {
998     /* See RFC 3484 for the details.  */
999     { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1000                                   0x0000, 0x0000, 0x0000, 0x0001 } } },
1001       128, 50 },
1002     { { .in6_u = { .u6_addr16 = { 0x2002, 0x0000, 0x0000, 0x0000,
1003                                   0x0000, 0x0000, 0x0000, 0x0000 } } },
1004       16, 30 },
1005     { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1006                                   0x0000, 0x0000, 0x0000, 0x0000 } } },
1007       96, 20 },
1008     { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1009                                   0x0000, 0xffff, 0x0000, 0x0000 } } },
1010       96, 10 },
1011     { { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1012                                   0x0000, 0x0000, 0x0000, 0x0000 } } },
1013       0, 40 }
1014   };
1015
1016
1017 static int
1018 match_prefix (const struct sockaddr_storage *ss, const struct prefixlist *list,
1019               int default_val)
1020 {
1021   int idx;
1022   struct sockaddr_in6 in6_mem;
1023   const struct sockaddr_in6 *in6;
1024
1025   if (ss->ss_family == PF_INET6)
1026     in6 = (const struct sockaddr_in6 *) ss;
1027   else if (ss->ss_family == PF_INET)
1028     {
1029       const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
1030
1031       /* Convert to IPv6 address.  */
1032       in6_mem.sin6_family = PF_INET6;
1033       in6_mem.sin6_port = in->sin_port;
1034       in6_mem.sin6_flowinfo = 0;
1035       if (in->sin_addr.s_addr == htonl (0x7f000001))
1036         in6_mem.sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
1037       else
1038         {
1039           /* Construct a V4-to-6 mapped address.  */
1040           memset (&in6_mem.sin6_addr, '\0', sizeof (in6_mem.sin6_addr));
1041           in6_mem.sin6_addr.s6_addr16[5] = 0xffff;
1042           in6_mem.sin6_addr.s6_addr32[3] = in->sin_addr.s_addr;
1043           in6_mem.sin6_scope_id = 0;
1044         }
1045
1046       in6 = &in6_mem;
1047     }
1048   else
1049     return default_val;
1050
1051   for (idx = 0; ; ++idx)
1052     {
1053       unsigned int bits = list[idx].bits;
1054       uint8_t *mask = list[idx].prefix.s6_addr;
1055       uint8_t *val = in6->sin6_addr.s6_addr;
1056
1057       while (bits > 8)
1058         {
1059           if (*mask != *val)
1060             break;
1061
1062           ++mask;
1063           ++val;
1064           bits -= 8;
1065         }
1066
1067       if (bits < 8)
1068         {
1069           if ((*mask & (0xff00 >> bits)) == (*val & (0xff00 >> bits)))
1070             /* Match!  */
1071             break;
1072         }
1073     }
1074
1075   return list[idx].val;
1076 }
1077
1078
1079 static int
1080 get_label (const struct sockaddr_storage *ss)
1081 {
1082   /* XXX What is a good default value?  */
1083   return match_prefix (ss, default_labels, INT_MAX);
1084 }
1085
1086
1087 static int
1088 get_precedence (const struct sockaddr_storage *ss)
1089 {
1090   /* XXX What is a good default value?  */
1091   return match_prefix (ss, default_precedence, 0);
1092 }
1093
1094
1095 static int
1096 rfc3484_sort (const void *p1, const void *p2)
1097 {
1098   const struct sort_result *a1 = (const struct sort_result *) p1;
1099   const struct sort_result *a2 = (const struct sort_result *) p2;
1100
1101   /* Rule 1: Avoid unusable destinations.
1102      We have the got_source_addr flag set if the destination is reachable.  */
1103   if (a1->got_source_addr && ! a2->got_source_addr)
1104     return -1;
1105   if (! a1->got_source_addr && a2->got_source_addr)
1106     return 1;
1107
1108
1109   /* Rule 2: Prefer matching scope.  Only interesting if both
1110      destination addresses are IPv6.  */
1111   int a1_dst_scope
1112     = get_scope ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1113
1114   int a2_dst_scope
1115     = get_scope ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1116
1117   if (a1->got_source_addr)
1118     {
1119       int a1_src_scope = get_scope (&a1->source_addr);
1120       int a2_src_scope = get_scope (&a2->source_addr);
1121
1122       if (a1_dst_scope == a1_src_scope && a2_dst_scope != a2_src_scope)
1123         return -1;
1124       if (a1_dst_scope != a1_src_scope && a2_dst_scope == a2_src_scope)
1125         return 1;
1126     }
1127
1128
1129   /* Rule 3: Avoid deprecated addresses.
1130      That's something only the kernel could decide.  */
1131
1132   /* Rule 4: Prefer home addresses.
1133      Another thing only the kernel can decide.  */
1134
1135   /* Rule 5: Prefer matching label.  */
1136   if (a1->got_source_addr)
1137     {
1138       int a1_dst_label
1139         = get_label ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1140       int a1_src_label = get_label (&a1->source_addr);
1141
1142       int a2_dst_label
1143         = get_label ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1144       int a2_src_label = get_label (&a2->source_addr);
1145
1146       if (a1_dst_label == a1_src_label && a2_dst_label != a2_src_label)
1147         return -1;
1148       if (a1_dst_label != a1_src_label && a2_dst_label == a2_src_label)
1149         return 1;
1150     }
1151
1152
1153   /* Rule 6: Prefer higher precedence.  */
1154   int a1_prec
1155     = get_precedence ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1156   int a2_prec
1157     = get_precedence ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1158
1159   if (a1_prec > a2_prec)
1160     return -1;
1161   if (a1_prec < a2_prec)
1162     return 1;
1163
1164
1165   /* Rule 7: Prefer native transport.
1166      XXX How to recognize tunnels?  */
1167
1168
1169   /* Rule 8: Prefer smaller scope.  */
1170   if (a1_dst_scope < a2_dst_scope)
1171     return -1;
1172   if (a1_dst_scope > a2_dst_scope)
1173     return 1;
1174
1175
1176   /* Rule 9: Use longest matching prefix.  */
1177   if (a1->got_source_addr
1178       && a1->dest_addr->ai_family == a2->dest_addr->ai_family)
1179     {
1180       int bit1 = 0;
1181       int bit2 = 0;
1182
1183       if (a1->dest_addr->ai_family == PF_INET)
1184         {
1185           assert (a1->source_addr.ss_family == PF_INET);
1186           assert (a2->source_addr.ss_family == PF_INET);
1187
1188           struct sockaddr_in *in1_dst;
1189           struct sockaddr_in *in1_src;
1190           struct sockaddr_in *in2_dst;
1191           struct sockaddr_in *in2_src;
1192
1193           in1_dst = (struct sockaddr_in *) a1->dest_addr->ai_addr;
1194           in1_src = (struct sockaddr_in *) &a1->source_addr;
1195           in2_dst = (struct sockaddr_in *) a2->dest_addr->ai_addr;
1196           in2_src = (struct sockaddr_in *) &a2->source_addr;
1197
1198           bit1 = ffs (in1_dst->sin_addr.s_addr ^ in1_src->sin_addr.s_addr);
1199           bit2 = ffs (in2_dst->sin_addr.s_addr ^ in2_src->sin_addr.s_addr);
1200         }
1201       else if (a1->dest_addr->ai_family == PF_INET6)
1202         {
1203           assert (a1->source_addr.ss_family == PF_INET6);
1204           assert (a2->source_addr.ss_family == PF_INET6);
1205
1206           struct sockaddr_in6 *in1_dst;
1207           struct sockaddr_in6 *in1_src;
1208           struct sockaddr_in6 *in2_dst;
1209           struct sockaddr_in6 *in2_src;
1210
1211           in1_dst = (struct sockaddr_in6 *) a1->dest_addr->ai_addr;
1212           in1_src = (struct sockaddr_in6 *) &a1->source_addr;
1213           in2_dst = (struct sockaddr_in6 *) a2->dest_addr->ai_addr;
1214           in2_src = (struct sockaddr_in6 *) &a2->source_addr;
1215
1216           int i;
1217           for (i = 0; i < 4; ++i)
1218             if (in1_dst->sin6_addr.s6_addr32[i]
1219                 != in1_src->sin6_addr.s6_addr32[i]
1220                 || (in2_dst->sin6_addr.s6_addr32[i]
1221                     != in2_src->sin6_addr.s6_addr32[i]))
1222               break;
1223
1224           if (i < 4)
1225             {
1226               bit1 = ffs (in1_dst->sin6_addr.s6_addr32[i]
1227                           ^ in1_src->sin6_addr.s6_addr32[i]);
1228               bit2 = ffs (in2_dst->sin6_addr.s6_addr32[i]
1229                           ^ in2_src->sin6_addr.s6_addr32[i]);
1230             }
1231         }
1232
1233       if (bit1 > bit2)
1234         return -1;
1235       if (bit1 < bit2)
1236         return 1;
1237     }
1238
1239
1240   /* Rule 10: Otherwise, leave the order unchanged.  */
1241   return 0;
1242 }
1243
1244
1245 int
1246 getaddrinfo (const char *name, const char *service,
1247              const struct addrinfo *hints, struct addrinfo **pai)
1248 {
1249   int i = 0, j = 0, last_i = 0;
1250   int nresults = 0;
1251   struct addrinfo *p = NULL, **end;
1252   struct gaih *g = gaih, *pg = NULL;
1253   struct gaih_service gaih_service, *pservice;
1254   struct addrinfo local_hints;
1255
1256   if (name != NULL && name[0] == '*' && name[1] == 0)
1257     name = NULL;
1258
1259   if (service != NULL && service[0] == '*' && service[1] == 0)
1260     service = NULL;
1261
1262   if (name == NULL && service == NULL)
1263     return EAI_NONAME;
1264
1265   if (hints == NULL)
1266     hints = &default_hints;
1267
1268   if (hints->ai_flags
1269       & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|AI_ADDRCONFIG|AI_V4MAPPED
1270 #ifdef HAVE_LIBIDN
1271           |AI_IDN
1272 #endif
1273           |AI_ALL))
1274     return EAI_BADFLAGS;
1275
1276   if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
1277     return EAI_BADFLAGS;
1278
1279   if (hints->ai_flags & AI_ADDRCONFIG)
1280     {
1281       /* Determine whether we have IPv4 or IPv6 interfaces or both.
1282          We cannot cache the results since new interfaces could be
1283          added at any time.  */
1284       bool seen_ipv4;
1285       bool seen_ipv6;
1286       __check_pf (&seen_ipv4, &seen_ipv6);
1287
1288       /* Now make a decision on what we return, if anything.  */
1289       if (hints->ai_family == PF_UNSPEC)
1290         {
1291           /* If we haven't seen both IPv4 and IPv6 interfaces we can
1292              narrow down the search.  */
1293           if (! seen_ipv4 || ! seen_ipv6)
1294             {
1295               local_hints = *hints;
1296               local_hints.ai_family = seen_ipv4 ? PF_INET : PF_INET6;
1297               hints = &local_hints;
1298             }
1299         }
1300       else if ((hints->ai_family == PF_INET && ! seen_ipv4)
1301                || (hints->ai_family == PF_INET6 && ! seen_ipv6))
1302         /* We cannot possibly return a valid answer.  */
1303         return EAI_NONAME;
1304     }
1305
1306   if (service && service[0])
1307     {
1308       char *c;
1309       gaih_service.name = service;
1310       gaih_service.num = strtoul (gaih_service.name, &c, 10);
1311       if (*c)
1312         gaih_service.num = -1;
1313       else
1314         /* Can't specify a numerical socket unless a protocol family was
1315            given. */
1316         if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
1317           return EAI_SERVICE;
1318       pservice = &gaih_service;
1319     }
1320   else
1321     pservice = NULL;
1322
1323   if (pai)
1324     end = &p;
1325   else
1326     end = NULL;
1327
1328   while (g->gaih)
1329     {
1330       if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
1331         {
1332           j++;
1333           if (pg == NULL || pg->gaih != g->gaih)
1334             {
1335               pg = g;
1336               i = g->gaih (name, pservice, hints, end);
1337               if (i != 0)
1338                 {
1339                   /* EAI_NODATA is a more specific result as it says that
1340                      we found a result but it is not usable.  */
1341                   if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA))
1342                     last_i = i;
1343
1344                   if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
1345                     {
1346                       ++g;
1347                       continue;
1348                     }
1349
1350                   freeaddrinfo (p);
1351
1352                   return -(i & GAIH_EAI);
1353                 }
1354               if (end)
1355                 while (*end)
1356                   {
1357                     end = &((*end)->ai_next);
1358                     ++nresults;
1359                   }
1360             }
1361         }
1362       ++g;
1363     }
1364
1365   if (j == 0)
1366     return EAI_FAMILY;
1367
1368   if (nresults > 1)
1369     {
1370       /* Sort results according to RFC 3484.  */
1371       struct sort_result results[nresults];
1372       struct addrinfo *q;
1373
1374       for (i = 0, q = p; q != NULL; ++i, q = q->ai_next)
1375         {
1376           results[i].dest_addr = q;
1377           results[i].got_source_addr = false;
1378
1379           /* We overwrite the type with SOCK_DGRAM since we do not
1380              want connect() to connect to the other side.  If we
1381              cannot determine the source address remember this
1382              fact.  */
1383           int fd = __socket (q->ai_family, SOCK_DGRAM, IPPROTO_IP);
1384           if (fd != -1)
1385             {
1386               socklen_t sl = sizeof (results[i].source_addr);
1387               if (__connect (fd, q->ai_addr, q->ai_addrlen) == 0
1388                   && __getsockname (fd,
1389                                     (struct sockaddr *) &results[i].source_addr,
1390                                     &sl) == 0)
1391                 results[i].got_source_addr = true;
1392
1393               close_not_cancel_no_status (fd);
1394             }
1395         }
1396
1397       /* We got all the source addresses we can get, now sort using
1398          the information.  */
1399       qsort (results, nresults, sizeof (results[0]), rfc3484_sort);
1400
1401       /* Queue the results up as they come out of sorting.  */
1402       q = p = results[0].dest_addr;
1403       for (i = 1; i < nresults; ++i)
1404         q = q->ai_next = results[i].dest_addr;
1405       q->ai_next = NULL;
1406     }
1407
1408   if (p)
1409     {
1410       *pai = p;
1411       return 0;
1412     }
1413
1414   if (pai == NULL && last_i == 0)
1415     return 0;
1416
1417   freeaddrinfo (p);
1418
1419   return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
1420 }
1421 libc_hidden_def (getaddrinfo)
1422
1423 static_link_warning (getaddrinfo)
1424
1425 void
1426 freeaddrinfo (struct addrinfo *ai)
1427 {
1428   struct addrinfo *p;
1429
1430   while (ai != NULL)
1431     {
1432       p = ai;
1433       ai = ai->ai_next;
1434       free (p);
1435     }
1436 }
1437 libc_hidden_def (freeaddrinfo)