source: trunk/libs/newlib/src/newlib/libc/sys/linux/net/getaddrinfo.c @ 444

Last change on this file since 444 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 44.4 KB
Line 
1/* The Inner Net License, Version 2.00
2
3  The author(s) grant permission for redistribution and use in source and
4binary forms, with or without modification, of the software and documentation
5provided that the following conditions are met:
6
70. 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.
111. All terms of the all other applicable copyrights and licenses must be
12   followed.
132. Redistributions of source code must retain the authors' copyright
14   notice(s), this list of conditions, and the following disclaimer.
153. 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.
184. [The copyright holder has authorized the removal of this clause.]
195. 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
23THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
24EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
27DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30ANY 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
32SOFTWARE, 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 <alloca.h>
39#include <sys/types.h>
40#include <assert.h>
41#include <errno.h>
42#include <ifaddrs.h>
43#include <netdb.h>
44#include <resolv.h>
45#include <stdbool.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <unistd.h>
50#include <arpa/inet.h>
51#include <sys/socket.h>
52#include <netinet/in.h>
53#include <sys/un.h>
54#include <sys/utsname.h>
55#include <net/if.h>
56#include <nsswitch.h>
57#include <not-cancel.h>
58#include <nscd/nscd-client.h>
59#include <nscd/nscd_proto.h>
60#include <limits.h>
61#include "local.h"
62
63#ifdef HAVE_LIBIDN
64extern int __idna_to_ascii_lz (const char *input, char **output, int flags);
65extern int __idna_to_unicode_lzlz (const char *input, char **output,
66                                   int flags);
67# include <libidn/idna.h>
68#endif
69
70#define GAIH_OKIFUNSPEC 0x0100
71#define GAIH_EAI        ~(GAIH_OKIFUNSPEC)
72
73#ifndef UNIX_PATH_MAX
74#define UNIX_PATH_MAX  108
75#endif
76
77struct gaih_service
78  {
79    const char *name;
80    int num;
81  };
82
83struct gaih_servtuple
84  {
85    struct gaih_servtuple *next;
86    int socktype;
87    int protocol;
88    int port;
89  };
90
91static const struct gaih_servtuple nullserv;
92
93struct gaih_addrtuple
94  {
95    struct gaih_addrtuple *next;
96    char *name;
97    int family;
98    uint32_t addr[4];
99    uint32_t scopeid;
100  };
101
102struct gaih_typeproto
103  {
104    int socktype;
105    int protocol;
106    char name[4];
107    int protoflag;
108  };
109
110/* Values for `protoflag'.  */
111#define GAI_PROTO_NOSERVICE     1
112#define GAI_PROTO_PROTOANY      2
113
114static const struct gaih_typeproto gaih_inet_typeproto[] =
115{
116  { 0, 0, "", 0 },
117  { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
118  { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
119  { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
120  { 0, 0, "", 0 }
121};
122
123struct gaih
124  {
125    int family;
126    int (*gaih)(const char *name, const struct gaih_service *service,
127                const struct addrinfo *req, struct addrinfo **pai);
128  };
129
130static const struct addrinfo default_hints =
131  {
132    .ai_flags = AI_DEFAULT,
133    .ai_family = PF_UNSPEC,
134    .ai_socktype = 0,
135    .ai_protocol = 0,
136    .ai_addrlen = 0,
137    .ai_addr = NULL,
138    .ai_canonname = NULL,
139    .ai_next = NULL
140  };
141
142#define s6_addr32 __u6_addr.__u6_addr32
143
144#if 0
145/* Using Unix sockets this way is a security risk.  */
146static int
147gaih_local (const char *name, const struct gaih_service *service,
148            const struct addrinfo *req, struct addrinfo **pai)
149{
150  struct utsname utsname;
151
152  if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
153    return GAIH_OKIFUNSPEC | -EAI_NONAME;
154
155  if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
156    if (uname (&utsname) < 0)
157      return -EAI_SYSTEM;
158
159  if (name != NULL)
160    {
161      if (strcmp(name, "localhost") &&
162          strcmp(name, "local") &&
163          strcmp(name, "unix") &&
164          strcmp(name, utsname.nodename))
165        return GAIH_OKIFUNSPEC | -EAI_NONAME;
166    }
167
168  if (req->ai_protocol || req->ai_socktype)
169    {
170      const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
171
172      while (tp->name[0]
173             && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
174                 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
175                 || (req->ai_protocol != 0
176                     && !(tp->protoflag & GAI_PROTO_PROTOANY)
177                     && req->ai_protocol != tp->protocol)))
178        ++tp;
179
180      if (! tp->name[0])
181        {
182          if (req->ai_socktype)
183            return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
184          else
185            return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
186        }
187    }
188
189  *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
190                 + ((req->ai_flags & AI_CANONNAME)
191                    ? (strlen(utsname.nodename) + 1): 0));
192  if (*pai == NULL)
193    return -EAI_MEMORY;
194
195  (*pai)->ai_next = NULL;
196  (*pai)->ai_flags = req->ai_flags;
197  (*pai)->ai_family = AF_LOCAL;
198  (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
199  (*pai)->ai_protocol = req->ai_protocol;
200  (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
201  (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
202
203#if SALEN
204  ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
205    sizeof (struct sockaddr_un);
206#endif /* SALEN */
207
208  ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
209  memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
210
211  if (service)
212    {
213      struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
214
215      if (strchr (service->name, '/') != NULL)
216        {
217          if (strlen (service->name) >= sizeof (sunp->sun_path))
218            return GAIH_OKIFUNSPEC | -EAI_SERVICE;
219
220          strcpy (sunp->sun_path, service->name);
221        }
222      else
223        {
224          if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
225              sizeof (sunp->sun_path))
226            return GAIH_OKIFUNSPEC | -EAI_SERVICE;
227
228          __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
229        }
230    }
231  else
232    {
233      /* This is a dangerous use of the interface since there is a time
234         window between the test for the file and the actual creation
235         (done by the caller) in which a file with the same name could
236         be created.  */
237      char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
238
239      if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
240                            0) != 0
241          || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
242        return -EAI_SYSTEM;
243    }
244
245  if (req->ai_flags & AI_CANONNAME)
246    (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
247                                   + sizeof (struct sockaddr_un),
248                                   utsname.nodename);
249  else
250    (*pai)->ai_canonname = NULL;
251  return 0;
252}
253#endif  /* 0 */
254
255static int
256gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
257               const struct addrinfo *req, struct gaih_servtuple *st)
258{
259  struct servent *s;
260  size_t tmpbuflen = 1024;
261  struct servent ts;
262  char *tmpbuf;
263  int r;
264
265  do
266    {
267      tmpbuf = alloca (tmpbuflen);
268
269      r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
270                             &s);
271      if (r != 0 || s == NULL)
272        {
273          if (r == ERANGE)
274            tmpbuflen *= 2;
275          else
276            return GAIH_OKIFUNSPEC | -EAI_SERVICE;
277        }
278    }
279  while (r);
280
281  st->next = NULL;
282  st->socktype = tp->socktype;
283  st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
284                  ? req->ai_protocol : tp->protocol);
285  st->port = s->s_port;
286
287  return 0;
288}
289
290#define gethosts(_family, _type) \
291 {                                                                            \
292  int i;                                                                      \
293  int herrno;                                                                 \
294  struct hostent th;                                                          \
295  struct hostent *h;                                                          \
296  char *localcanon = NULL;                                                    \
297  no_data = 0;                                                                \
298  while (1) {                                                                 \
299    rc = 0;                                                                   \
300    status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf, tmpbuflen,        \
301                                &rc, &herrno, NULL, &localcanon));            \
302    if (rc != ERANGE || herrno != NETDB_INTERNAL)                             \
303      break;                                                                  \
304    tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);                \
305  }                                                                           \
306  if (status == NSS_STATUS_SUCCESS && rc == 0)                                \
307    h = &th;                                                                  \
308  else                                                                        \
309    h = NULL;                                                                 \
310  if (rc != 0)                                                                \
311    {                                                                         \
312      if (herrno == NETDB_INTERNAL)                                           \
313        {                                                                     \
314          h_errno = (herrno);                                         \
315          return -EAI_SYSTEM;                                                 \
316        }                                                                     \
317      if (herrno == TRY_AGAIN)                                                \
318        no_data = EAI_AGAIN;                                                  \
319      else                                                                    \
320        no_data = herrno == NO_DATA;                                          \
321    }                                                                         \
322  else if (h != NULL)                                                         \
323    {                                                                         \
324      for (i = 0; h->h_addr_list[i]; i++)                                     \
325        {                                                                     \
326          if (*pat == NULL)                                                   \
327            {                                                                 \
328              *pat = alloca (sizeof (struct gaih_addrtuple));                 \
329              (*pat)->scopeid = 0;                                            \
330            }                                                                 \
331          uint32_t *addr = (*pat)->addr;                                      \
332          (*pat)->next = NULL;                                                \
333          if (i == 0)                                                         \
334            {                                                                 \
335              (*pat)->name = alloca (strlen (h->h_name) + 1);                 \
336              strcpy ((*pat)->name, h->h_name);                               \
337            }                                                                 \
338          else                                                                \
339              (*pat)->name = NULL;                                            \
340          if (_family == AF_INET && req->ai_family == AF_INET6)               \
341            {                                                                 \
342              (*pat)->family = AF_INET6;                                      \
343              addr[3] = *(uint32_t *) h->h_addr_list[i];                      \
344              addr[2] = htonl (0xffff);                                       \
345              addr[1] = 0;                                                    \
346              addr[0] = 0;                                                    \
347            }                                                                 \
348          else                                                                \
349            {                                                                 \
350              (*pat)->family = _family;                                       \
351              memcpy (addr, h->h_addr_list[i], sizeof(_type));                \
352            }                                                                 \
353          pat = &((*pat)->next);                                              \
354        }                                                                     \
355                                                                              \
356      if (localcanon != NULL && canon == NULL)                                \
357        {                                                                     \
358          canon = alloca (strlen (localcanon) + 1);                           \
359          strcpy (canon, localcanon);                                         \
360        }                                                                     \
361                                                                              \
362      if (_family == AF_INET6 && i > 0)                                       \
363        got_ipv6 = true;                                                      \
364    }                                                                         \
365 }
366
367
368typedef enum nss_status (*nss_gethostbyname3_r)
369  (const char *name, int af, struct hostent *host,
370   char *buffer, size_t buflen, int *errnop,
371   int *h_errnop, int32_t *ttlp, char **canonp);
372typedef enum nss_status (*nss_getcanonname_r)
373  (const char *name, char *buffer, size_t buflen, char **result,
374   int *errnop, int *h_errnop);
375extern service_user *__nss_hosts_database attribute_hidden;
376
377static int
378gaih_inet (const char *name, const struct gaih_service *service,
379           const struct addrinfo *req, struct addrinfo **pai)
380{
381  const struct gaih_typeproto *tp = gaih_inet_typeproto;
382  struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
383  struct gaih_addrtuple *at = NULL;
384  int rc;
385  bool got_ipv6 = false;
386  const char *canon = NULL;
387  const char *orig_name = name;
388
389  if (req->ai_protocol || req->ai_socktype)
390    {
391      ++tp;
392
393      while (tp->name[0]
394             && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
395                 || (req->ai_protocol != 0
396                     && !(tp->protoflag & GAI_PROTO_PROTOANY)
397                     && req->ai_protocol != tp->protocol)))
398        ++tp;
399
400      if (! tp->name[0])
401        {
402          if (req->ai_socktype)
403            return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
404          else
405            return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
406        }
407    }
408
409  if (service != NULL)
410    {
411      if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
412        return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
413
414      if (service->num < 0)
415        {
416          if (tp->name[0])
417            {
418              st = (struct gaih_servtuple *)
419                alloca (sizeof (struct gaih_servtuple));
420
421              if ((rc = gaih_inet_serv (service->name, tp, req, st)))
422                return rc;
423            }
424          else
425            {
426              struct gaih_servtuple **pst = &st;
427              for (tp++; tp->name[0]; tp++)
428                {
429                  struct gaih_servtuple *newp;
430
431                  if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
432                    continue;
433
434                  if (req->ai_socktype != 0
435                      && req->ai_socktype != tp->socktype)
436                    continue;
437                  if (req->ai_protocol != 0
438                      && !(tp->protoflag & GAI_PROTO_PROTOANY)
439                      && req->ai_protocol != tp->protocol)
440                    continue;
441
442                  newp = (struct gaih_servtuple *)
443                    alloca (sizeof (struct gaih_servtuple));
444
445                  if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
446                    {
447                      if (rc & GAIH_OKIFUNSPEC)
448                        continue;
449                      return rc;
450                    }
451
452                  *pst = newp;
453                  pst = &(newp->next);
454                }
455              if (st == (struct gaih_servtuple *) &nullserv)
456                return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
457            }
458        }
459      else
460        {
461          if (req->ai_socktype || req->ai_protocol)
462            {
463              st = alloca (sizeof (struct gaih_servtuple));
464              st->next = NULL;
465              st->socktype = tp->socktype;
466              st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
467                              ? req->ai_protocol : tp->protocol);
468              st->port = htons (service->num);
469            }
470          else
471            {
472              /* Neither socket type nor protocol is set.  Return all
473                 socket types we know about.  */
474              struct gaih_servtuple **lastp = &st;
475              for (tp = gaih_inet_typeproto + 1; tp->name[0]; ++tp)
476                if ((tp->protoflag & GAI_PROTO_NOSERVICE) == 0)
477                  {
478                    struct gaih_servtuple *newp;
479
480                    newp = alloca (sizeof (struct gaih_servtuple));
481                    newp->next = NULL;
482                    newp->socktype = tp->socktype;
483                    newp->protocol = tp->protocol;
484                    newp->port = htons (service->num);
485
486                    *lastp = newp;
487                    lastp = &newp->next;
488                  }
489            }
490        }
491    }
492  else if (req->ai_socktype || req->ai_protocol)
493    {
494      st = alloca (sizeof (struct gaih_servtuple));
495      st->next = NULL;
496      st->socktype = tp->socktype;
497      st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
498                      ? req->ai_protocol : tp->protocol);
499      st->port = 0;
500    }
501  else
502    {
503      /* Neither socket type nor protocol is set.  Return all socket types
504         we know about.  */
505      struct gaih_servtuple **lastp = &st;
506      for (++tp; tp->name[0]; ++tp)
507        {
508          struct gaih_servtuple *newp;
509
510          newp = alloca (sizeof (struct gaih_servtuple));
511          newp->next = NULL;
512          newp->socktype = tp->socktype;
513          newp->protocol = tp->protocol;
514          newp->port = 0;
515
516          *lastp = newp;
517          lastp = &newp->next;
518        }
519    }
520
521  if (name != NULL)
522    {
523      at = alloca (sizeof (struct gaih_addrtuple));
524
525      at->family = AF_UNSPEC;
526      at->scopeid = 0;
527      at->next = NULL;
528
529#ifdef HAVE_LIBIDN
530      if (req->ai_flags & AI_IDN)
531        {
532          int idn_flags = 0;
533          if (req->ai_flags & AI_IDN_ALLOW_UNASSIGNED)
534            idn_flags |= IDNA_ALLOW_UNASSIGNED;
535          if (req->ai_flags & AI_IDN_USE_STD3_ASCII_RULES)
536            idn_flags |= IDNA_USE_STD3_ASCII_RULES;
537
538          char *p = NULL;
539          rc = __idna_to_ascii_lz (name, &p, idn_flags);
540          if (rc != IDNA_SUCCESS)
541            {
542              if (rc == IDNA_MALLOC_ERROR)
543                return -EAI_MEMORY;
544              if (rc == IDNA_DLOPEN_ERROR)
545                return -EAI_SYSTEM;
546              return -EAI_IDN_ENCODE;
547            }
548          /* In case the output string is the same as the input string
549             no new string has been allocated.  */
550          if (p != name)
551            {
552              name = alloca (strlen (p) + 1);
553              strcpy (name, p);
554              free (p);
555            }
556        }
557#endif
558
559      if (inet_aton (name, (struct in_addr *) at->addr) != 0)
560        {
561          if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
562            at->family = AF_INET;
563          else if (req->ai_family == AF_INET6 && req->ai_flags & AI_V4MAPPED)
564            {
565              at->addr[3] = at->addr[0];
566              at->addr[2] = htonl (0xffff);
567              at->addr[1] = 0;
568              at->addr[0] = 0;
569              at->family = AF_INET6;
570            }
571          else
572            return -EAI_ADDRFAMILY;
573
574        dupname:
575          if (req->ai_flags & AI_CANONNAME)
576            {
577              canon = strdup (name);
578              if (canon == NULL)
579                return -EAI_MEMORY;
580            }
581        }
582
583      if (at->family == AF_UNSPEC)
584        {
585          char *scope_delim;
586          char *namebuf = alloca (strlen (name) + 1);
587          strcpy (namebuf, name);
588
589          scope_delim = strchr (namebuf, SCOPE_DELIMITER);
590          if (scope_delim != NULL)
591            *scope_delim = '\0';
592
593          if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
594            {
595              if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
596                at->family = AF_INET6;
597              else if (req->ai_family == AF_INET
598                       && IN6_IS_ADDR_V4MAPPED ((struct in6_addr *)at->addr))
599                {
600                  at->addr[0] = at->addr[3];
601                  at->family = AF_INET;
602                }
603              else
604                return -EAI_ADDRFAMILY;
605
606              if (scope_delim != NULL)
607                {
608                  int try_numericscope = 0;
609                  if (IN6_IS_ADDR_LINKLOCAL ((struct in6_addr *)at->addr)
610                      || IN6_IS_ADDR_MC_LINKLOCAL ((struct in6_addr *)at->addr))
611                    {
612                      at->scopeid = if_nametoindex (scope_delim + 1);
613                      if (at->scopeid == 0)
614                        try_numericscope = 1;
615                    }
616                  else
617                    try_numericscope = 1;
618
619                  if (try_numericscope != 0)
620                    {
621                      char *end;
622                      assert (sizeof (uint32_t) <= sizeof (unsigned long));
623                      at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
624                                                        10);
625                      if (*end != '\0')
626                        return GAIH_OKIFUNSPEC | -EAI_NONAME;
627                    }
628                }
629
630              goto dupname;
631            }
632        }
633
634      if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
635        {
636          struct gaih_addrtuple **pat = &at;
637          int no_data = 0;
638          int no_inet6_data = 0;
639          service_user *nip = NULL;
640          enum nss_status inet6_status = NSS_STATUS_UNAVAIL;
641          enum nss_status status = NSS_STATUS_UNAVAIL;
642          int no_more;
643          int old_res_options;
644
645          /* If we do not have to look for IPv4 and IPv6 together, use
646             the simple, old functions.  */
647          if (req->ai_family == AF_INET || req->ai_family == AF_INET6)
648            {
649              int family = req->ai_family;
650              size_t tmpbuflen = 512;
651              char *tmpbuf = alloca (tmpbuflen);
652              int rc;
653              struct hostent th;
654              struct hostent *h;
655              int herrno;
656
657            simple_again:
658              while (1)
659                {
660                  rc = __gethostbyname2_r (name, family, &th, tmpbuf,
661                                           tmpbuflen, &h, &herrno);
662                  if (rc != ERANGE || herrno != NETDB_INTERNAL)
663                    break;
664                  tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
665                }
666
667              if (rc == 0)
668                {
669                  if (h == NULL)
670                    {
671                      if (req->ai_family == AF_INET6
672                          && (req->ai_flags & AI_V4MAPPED)
673                          && family == AF_INET6)
674                        {
675                          /* Try again, this time looking for IPv4
676                             addresses.  */
677                          family = AF_INET;
678                          goto simple_again;
679                        }
680                    }
681                  else
682                    {
683                      /* We found data, now convert it into the list.  */
684                      int i = 0;
685                      for (i = 0; h->h_addr_list[i]; ++i)
686                        {
687                          if (*pat == NULL)
688                            {
689                              *pat = alloca (sizeof (struct gaih_addrtuple));
690                              (*pat)->scopeid = 0;
691                            }
692                          (*pat)->next = NULL;
693                          (*pat)->family = req->ai_family;
694                          if (family == req->ai_family)
695                            memcpy ((*pat)->addr, h->h_addr_list[i],
696                                    h->h_length);
697                          else
698                            {
699                              int32_t *addr = (uint32_t *) (*pat)->addr;
700                              addr[3] = *(uint32_t *) h->h_addr_list[i];
701                              addr[2] = htonl (0xffff);
702                              addr[1] = 0;
703                              addr[0] = 0;
704                            }
705                          pat = &((*pat)->next);
706                        }
707                    }
708                }
709              else
710                {
711                  if (herrno == NETDB_INTERNAL)
712                    {
713                      h_errno = (herrno);
714                      return -EAI_SYSTEM;
715                    }
716                  if (herrno == TRY_AGAIN)
717                    {
718                      return -EAI_AGAIN;
719                    }
720                  /* We made requests but they turned out no data.
721                     The name is known, though.  */
722                  return (GAIH_OKIFUNSPEC | -EAI_NODATA);
723                }
724
725              goto process_list;
726            }
727
728#ifdef USE_NSCD
729          if (__nss_not_use_nscd_hosts > 0
730              && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
731            __nss_not_use_nscd_hosts = 0;
732
733          if (!__nss_not_use_nscd_hosts)
734            {
735              /* Try to use nscd.  */
736              struct nscd_ai_result *air = NULL;
737              int herrno;
738              int err = __nscd_getai (name, &air, &herrno);
739              if (air != NULL)
740                {
741                  /* Transform into gaih_addrtuple list.  */
742                  bool added_canon = (req->ai_flags & AI_CANONNAME) == 0;
743                  char *addrs = air->addrs;
744
745                  for (int i = 0; i < air->naddrs; ++i)
746                    {
747                      socklen_t size = (air->family[i] == AF_INET
748                                        ? INADDRSZ : IN6ADDRSZ);
749                      if (*pat == NULL)
750                        {
751                          *pat = alloca (sizeof (struct gaih_addrtuple));
752                          (*pat)->scopeid = 0;
753                        }
754                      uint32_t *pataddr = (*pat)->addr;
755                      (*pat)->next = NULL;
756                      if (added_canon || air->canon == NULL)
757                        (*pat)->name = NULL;
758                      else {
759                        canon = (*pat)->name = alloca (strlen (air->canon) + 1);
760                        strcpy (canon, air->canon);
761                      }
762
763                      if (air->family[i] == AF_INET
764                          && req->ai_family == AF_INET6
765                          && (req->ai_flags & AI_V4MAPPED))
766                        {
767                          (*pat)->family = AF_INET6;
768                          pataddr[3] = *(uint32_t *) addrs;
769                          pataddr[2] = htonl (0xffff);
770                          pataddr[1] = 0;
771                          pataddr[0] = 0;
772                          pat = &((*pat)->next);
773                          added_canon = true;
774                        }
775                      else if (req->ai_family == AF_UNSPEC
776                               || air->family[i] == req->ai_family)
777                        {
778                          (*pat)->family = air->family[i];
779                          memcpy (pataddr, addrs, size);
780                          pat = &((*pat)->next);
781                          added_canon = true;
782                          if (air->family[i] == AF_INET6)
783                            got_ipv6 = true;
784                        }
785                      addrs += size;
786                    }
787
788                  free (air);
789
790                  if (at->family == AF_UNSPEC)
791                    return (GAIH_OKIFUNSPEC | -EAI_NONAME);
792
793                  goto process_list;
794                }
795              else if (err != 0 && __nss_not_use_nscd_hosts == 0)
796                {
797                  if (herrno == NETDB_INTERNAL && errno == ENOMEM)
798                    return -EAI_MEMORY;
799                  if (herrno == TRY_AGAIN)
800                    return -EAI_AGAIN;
801                  return -EAI_SYSTEM;
802                }
803            }
804#endif
805
806          if (__nss_hosts_database != NULL)
807            {
808              no_more = 0;
809              nip = __nss_hosts_database;
810            }
811          else
812            no_more = __nss_database_lookup ("hosts", NULL,
813                                             "dns [!UNAVAIL=return] files",
814                                             &nip);
815
816          if (__res_maybe_init (&_res, 0) == -1)
817            no_more = 1;
818
819          /* If we are looking for both IPv4 and IPv6 address we don't
820             want the lookup functions to automatically promote IPv4
821             addresses to IPv6 addresses.  Currently this is decided
822             by setting the RES_USE_INET6 bit in _res.options.  */
823          old_res_options = _res.options;
824          _res.options &= ~RES_USE_INET6;
825
826          size_t tmpbuflen = 512;
827          char *tmpbuf = alloca (tmpbuflen);
828
829          while (!no_more)
830            {
831              nss_gethostbyname3_r fct = NULL;
832              if (req->ai_flags & AI_CANONNAME)
833                /* No need to use this function if we do not look for
834                   the canonical name.  The function does not exist in
835                   all NSS modules and therefore the lookup would
836                   often fail.  */
837                fct = __nss_lookup_function (nip, "gethostbyname3_r");
838              if (fct == NULL)
839                /* We are cheating here.  The gethostbyname2_r function does
840                   not have the same interface as gethostbyname3_r but the
841                   extra arguments the latter takes are added at the end.
842                   So the gethostbyname2_r code will just ignore them.  */
843                fct = __nss_lookup_function (nip, "gethostbyname2_r");
844
845              if (fct != NULL)
846                {
847                  if (req->ai_family == AF_INET6
848                      || req->ai_family == AF_UNSPEC)
849                    {
850                      gethosts (AF_INET6, struct in6_addr);
851                      no_inet6_data = no_data;
852                      inet6_status = status;
853                    }
854                  if (req->ai_family == AF_INET
855                      || req->ai_family == AF_UNSPEC
856                      || (req->ai_family == AF_INET6
857                          && (req->ai_flags & AI_V4MAPPED)
858                          /* Avoid generating the mapped addresses if we
859                             know we are not going to need them.  */
860                          && ((req->ai_flags & AI_ALL) || !got_ipv6)))
861                    {
862                      gethosts (AF_INET, struct in_addr);
863
864                      if (req->ai_family == AF_INET)
865                        {
866                          no_inet6_data = no_data;
867                          inet6_status = status;
868                        }
869                    }
870
871                  /* If we found one address for AF_INET or AF_INET6,
872                     don't continue the search.  */
873                  if (inet6_status == NSS_STATUS_SUCCESS
874                      || status == NSS_STATUS_SUCCESS)
875                    {
876                      if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
877                        {
878                          /* If we need the canonical name, get it
879                             from the same service as the result.  */
880                          nss_getcanonname_r cfct;
881                          int herrno;
882
883                          cfct = __nss_lookup_function (nip, "getcanonname_r");
884                          if (cfct != NULL)
885                            {
886                              const size_t max_fqdn_len = 256;
887                              char *buf = alloca (max_fqdn_len);
888                              char *s;
889
890                              if (DL_CALL_FCT (cfct, (at->name ?: name, buf,
891                                                      max_fqdn_len, &s, &rc,
892                                                      &herrno))
893                                  == NSS_STATUS_SUCCESS)
894                                canon = s;
895                              else
896                                /* Set to name now to avoid using
897                                   gethostbyaddr.  */
898                                canon = name;
899                            }
900                        }
901
902                      break;
903                    }
904
905                  /* We can have different states for AF_INET and
906                     AF_INET6.  Try to find a useful one for both.  */
907                  if (inet6_status == NSS_STATUS_TRYAGAIN)
908                    status = NSS_STATUS_TRYAGAIN;
909                  else if (status == NSS_STATUS_UNAVAIL &&
910                           inet6_status != NSS_STATUS_UNAVAIL)
911                    status = inet6_status;
912                }
913
914              if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
915                break;
916
917              if (nip->next == NULL)
918                no_more = -1;
919              else
920                nip = nip->next;
921            }
922
923          _res.options = old_res_options;
924
925          if (no_data != 0 && no_inet6_data != 0)
926            {
927              /* If both requests timed out report this.  */
928              if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
929                return -EAI_AGAIN;
930
931              /* We made requests but they turned out no data.  The name
932                 is known, though.  */
933              return (GAIH_OKIFUNSPEC | -EAI_NODATA);
934            }
935        }
936
937    process_list:
938      if (at->family == AF_UNSPEC)
939        return (GAIH_OKIFUNSPEC | -EAI_NONAME);
940    }
941  else
942    {
943      struct gaih_addrtuple *atr;
944      atr = at = alloca (sizeof (struct gaih_addrtuple));
945      memset (at, '\0', sizeof (struct gaih_addrtuple));
946
947      if (req->ai_family == AF_UNSPEC)
948        {
949          at->next = alloca (sizeof (struct gaih_addrtuple));
950          memset (at->next, '\0', sizeof (struct gaih_addrtuple));
951        }
952
953      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
954        {
955          at->family = AF_INET6;
956          if ((req->ai_flags & AI_PASSIVE) == 0)
957            memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
958          atr = at->next;
959        }
960
961      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
962        {
963          atr->family = AF_INET;
964          if ((req->ai_flags & AI_PASSIVE) == 0)
965            atr->addr[0] = htonl (INADDR_LOOPBACK);
966        }
967    }
968
969  if (pai == NULL)
970    return 0;
971
972  {
973    struct gaih_servtuple *st2;
974    struct gaih_addrtuple *at2 = at;
975    size_t socklen;
976    sa_family_t family;
977
978    /*
979      buffer is the size of an unformatted IPv6 address in printable format.
980     */
981    while (at2 != NULL)
982      {
983        /* Only the first entry gets the canonical name.  */
984        if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
985          {
986            if (canon == NULL)
987              {
988                struct hostent *h = NULL;
989                int herrno;
990                struct hostent th;
991                size_t tmpbuflen = 512;
992                char *tmpbuf = NULL;
993
994                do
995                  {
996                    tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2);
997                    rc = __gethostbyaddr_r (at2->addr,
998                                            ((at2->family == AF_INET6)
999                                             ? sizeof (struct in6_addr)
1000                                             : sizeof (struct in_addr)),
1001                                            at2->family, &th, tmpbuf,
1002                                            tmpbuflen, &h, &herrno);
1003                  }
1004                while (rc == ERANGE && herrno == NETDB_INTERNAL);
1005
1006                if (rc != 0 && herrno == NETDB_INTERNAL)
1007                  {
1008                    h_errno = (herrno);
1009                    return -EAI_SYSTEM;
1010                  }
1011
1012                if (h != NULL)
1013                  canon = h->h_name;
1014                else
1015                  {
1016                    assert (orig_name != NULL);
1017                    /* If the canonical name cannot be determined, use
1018                       the passed in string.  */
1019                    canon = orig_name;
1020                  }
1021              }
1022
1023#ifdef HAVE_LIBIDN
1024            if (req->ai_flags & AI_CANONIDN)
1025              {
1026                int idn_flags = 0;
1027                if (req->ai_flags & AI_IDN_ALLOW_UNASSIGNED)
1028                  idn_flags |= IDNA_ALLOW_UNASSIGNED;
1029                if (req->ai_flags & AI_IDN_USE_STD3_ASCII_RULES)
1030                  idn_flags |= IDNA_USE_STD3_ASCII_RULES;
1031
1032                char *out;
1033                int rc = __idna_to_unicode_lzlz (canon, &out, idn_flags);
1034                if (rc != IDNA_SUCCESS)
1035                  {
1036                    if (rc == IDNA_MALLOC_ERROR)
1037                      return -EAI_MEMORY;
1038                    if (rc == IDNA_DLOPEN_ERROR)
1039                      return -EAI_SYSTEM;
1040                    return -EAI_IDN_ENCODE;
1041                  }
1042                /* In case the output string is the same as the input
1043                   string no new string has been allocated.  Otherwise
1044                   make a copy.  */
1045                if (out == canon)
1046                  goto make_copy;
1047              }
1048            else
1049#endif
1050              {
1051#ifdef HAVE_LIBIDN
1052              make_copy:
1053#endif
1054                canon = strdup (canon);
1055                if (canon == NULL)
1056                  return -EAI_MEMORY;
1057              }
1058          }
1059
1060        if (at2->family == AF_INET6)
1061          {
1062            family = AF_INET6;
1063            socklen = sizeof (struct sockaddr_in6);
1064
1065            /* If we looked up IPv4 mapped address discard them here if
1066               the caller isn't interested in all address and we have
1067               found at least one IPv6 address.  */
1068            if (got_ipv6
1069                && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
1070                && IN6_IS_ADDR_V4MAPPED ((struct in6_addr *)at2->addr))
1071              goto ignore;
1072          }
1073        else
1074          {
1075            family = AF_INET;
1076            socklen = sizeof (struct sockaddr_in);
1077          }
1078
1079        for (st2 = st; st2 != NULL; st2 = st2->next)
1080          {
1081            struct addrinfo *ai;
1082            ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
1083            if (ai == NULL)
1084              return -EAI_MEMORY;
1085
1086            ai->ai_flags = req->ai_flags;
1087            ai->ai_family = family;
1088            ai->ai_socktype = st2->socktype;
1089            ai->ai_protocol = st2->protocol;
1090            ai->ai_addrlen = socklen;
1091            ai->ai_addr = (void *) (ai + 1);
1092
1093            /* We only add the canonical name once.  */
1094            ai->ai_canonname = (char *) canon;
1095            canon = NULL;
1096
1097#if SALEN
1098            ai->ai_addr->sa_len = socklen;
1099#endif /* SALEN */
1100            ai->ai_addr->sa_family = family;
1101
1102            if (family == AF_INET6)
1103              {
1104                struct sockaddr_in6 *sin6p =
1105                  (struct sockaddr_in6 *) ai->ai_addr;
1106
1107                sin6p->sin6_port = st2->port;
1108                sin6p->sin6_flowinfo = 0;
1109                memcpy (&sin6p->sin6_addr,
1110                        at2->addr, sizeof (struct in6_addr));
1111                sin6p->sin6_scope_id = at2->scopeid;
1112              }
1113            else
1114              {
1115                struct sockaddr_in *sinp =
1116                  (struct sockaddr_in *) ai->ai_addr;
1117                sinp->sin_port = st2->port;
1118                memcpy (&sinp->sin_addr,
1119                        at2->addr, sizeof (struct in_addr));
1120                memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
1121              }
1122
1123            pai = &(ai->ai_next);
1124          }
1125        *pai = NULL;
1126
1127      ignore:
1128        at2 = at2->next;
1129      }
1130  }
1131  return 0;
1132}
1133
1134static struct gaih gaih[] =
1135  {
1136    { PF_INET6, gaih_inet },
1137    { PF_INET, gaih_inet },
1138#if 0
1139    { PF_LOCAL, gaih_local },
1140#endif
1141    { PF_UNSPEC, NULL }
1142  };
1143
1144struct sort_result
1145{
1146  struct addrinfo *dest_addr;
1147  struct sockaddr_storage source_addr;
1148  uint8_t source_addr_len;
1149  bool got_source_addr;
1150};
1151
1152
1153static int
1154get_scope (const struct sockaddr_storage *ss)
1155{
1156  int scope;
1157  if (ss->ss_family == PF_INET6)
1158    {
1159      const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *) ss;
1160
1161      if (! IN6_IS_ADDR_MULTICAST (&in6->sin6_addr))
1162        {
1163          if (IN6_IS_ADDR_LINKLOCAL (&in6->sin6_addr))
1164            scope = 2;
1165          else if (IN6_IS_ADDR_SITELOCAL (&in6->sin6_addr))
1166            scope = 5;
1167          else
1168            /* XXX Is this the correct default behavior?  */
1169            scope = 14;
1170        }
1171      else
1172        scope = in6->sin6_addr.s6_addr[1] & 0xf;
1173    }
1174  else if (ss->ss_family == PF_INET)
1175    {
1176      const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
1177      const uint8_t *addr = (const uint8_t *) &in->sin_addr;
1178
1179      /* RFC 3484 specifies how to map IPv6 addresses to scopes.
1180         169.254/16 and 127/8 are link-local.  */
1181      if ((addr[0] == 169 && addr[1] == 254) || addr[0] == 127)
1182        scope = 2;
1183      else if (addr[0] == 10 || (addr[0] == 172 && addr[1] == 16)
1184               || (addr[0] == 192 && addr[1] == 168))
1185        scope = 5;
1186      else
1187        scope = 14;
1188    }
1189  else
1190    /* XXX What is a good default?  */
1191    scope = 15;
1192
1193  return scope;
1194}
1195
1196
1197/* XXX The system administrator should be able to install other
1198   tables.  We need to make this configurable.  The problem is that
1199   the kernel is also involved since it needs the same table.  */
1200static const struct prefixlist
1201{
1202  struct in6_addr prefix;
1203  unsigned int bits;
1204  int val;
1205} default_labels[] =
1206  {
1207    /* See RFC 3484 for the details.  */
1208    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1209                                        0x0000, 0x0000, 0x0000, 0x0001 } } },
1210      128, 0 },
1211    { { .__u6_addr = { .__u6_addr16 = { 0x2002, 0x0000, 0x0000, 0x0000,
1212                                       0x0000, 0x0000, 0x0000, 0x0000 } } },
1213      16, 2 },
1214    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1215                                       0x0000, 0x0000, 0x0000, 0x0000 } } },
1216      96, 3 },
1217    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1218                                       0x0000, 0xffff, 0x0000, 0x0000 } } },
1219      96, 4 },
1220    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1221                                       0x0000, 0x0000, 0x0000, 0x0000 } } },
1222      0, 1 }
1223  };
1224
1225
1226static const struct prefixlist default_precedence[] =
1227  {
1228    /* See RFC 3484 for the details.  */
1229    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1230                                       0x0000, 0x0000, 0x0000, 0x0001 } } },
1231      128, 50 },
1232    { { .__u6_addr = { .__u6_addr16 = { 0x2002, 0x0000, 0x0000, 0x0000,
1233                                       0x0000, 0x0000, 0x0000, 0x0000 } } },
1234      16, 30 },
1235    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1236                                       0x0000, 0x0000, 0x0000, 0x0000 } } },
1237      96, 20 },
1238    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1239                                       0x0000, 0xffff, 0x0000, 0x0000 } } },
1240      96, 10 },
1241    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1242                                       0x0000, 0x0000, 0x0000, 0x0000 } } },
1243      0, 40 }
1244  };
1245
1246
1247static int
1248match_prefix (const struct sockaddr_storage *ss, const struct prefixlist *list,
1249              int default_val)
1250{
1251  int idx;
1252  struct sockaddr_in6 in6_mem;
1253  const struct sockaddr_in6 *in6;
1254
1255  if (ss->ss_family == PF_INET6)
1256    in6 = (const struct sockaddr_in6 *) ss;
1257  else if (ss->ss_family == PF_INET)
1258    {
1259      const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
1260
1261      /* Convert to IPv6 address.  */
1262      in6_mem.sin6_family = PF_INET6;
1263      in6_mem.sin6_port = in->sin_port;
1264      in6_mem.sin6_flowinfo = 0;
1265      if (in->sin_addr.s_addr == htonl (0x7f000001))
1266        in6_mem.sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
1267      else
1268        {
1269          /* Construct a V4-to-6 mapped address.  */
1270          memset (&in6_mem.sin6_addr, '\0', sizeof (in6_mem.sin6_addr));
1271          in6_mem.sin6_addr.__u6_addr.__u6_addr16[5] = 0xffff;
1272          in6_mem.sin6_addr.__u6_addr.__u6_addr32[3] = in->sin_addr.s_addr;
1273          in6_mem.sin6_scope_id = 0;
1274        }
1275
1276      in6 = &in6_mem;
1277    }
1278  else
1279    return default_val;
1280
1281  for (idx = 0; ; ++idx)
1282    {
1283      unsigned int bits = list[idx].bits;
1284      uint8_t *mask = list[idx].prefix.s6_addr;
1285      uint8_t *val = in6->sin6_addr.s6_addr;
1286
1287      while (bits > 8)
1288        {
1289          if (*mask != *val)
1290            break;
1291
1292          ++mask;
1293          ++val;
1294          bits -= 8;
1295        }
1296
1297      if (bits < 8)
1298        {
1299          if ((*mask & (0xff00 >> bits)) == (*val & (0xff00 >> bits)))
1300            /* Match!  */
1301            break;
1302        }
1303    }
1304
1305  return list[idx].val;
1306}
1307
1308
1309static int
1310get_label (const struct sockaddr_storage *ss)
1311{
1312  /* XXX What is a good default value?  */
1313  return match_prefix (ss, default_labels, INT_MAX);
1314}
1315
1316
1317static int
1318get_precedence (const struct sockaddr_storage *ss)
1319{
1320  /* XXX What is a good default value?  */
1321  return match_prefix (ss, default_precedence, 0);
1322}
1323
1324
1325static int
1326rfc3484_sort (const void *p1, const void *p2)
1327{
1328  const struct sort_result *a1 = (const struct sort_result *) p1;
1329  const struct sort_result *a2 = (const struct sort_result *) p2;
1330
1331  /* Rule 1: Avoid unusable destinations.
1332     We have the got_source_addr flag set if the destination is reachable.  */
1333  if (a1->got_source_addr && ! a2->got_source_addr)
1334    return -1;
1335  if (! a1->got_source_addr && a2->got_source_addr)
1336    return 1;
1337
1338
1339  /* Rule 2: Prefer matching scope.  Only interesting if both
1340     destination addresses are IPv6.  */
1341  int a1_dst_scope
1342    = get_scope ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1343
1344  int a2_dst_scope
1345    = get_scope ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1346
1347  if (a1->got_source_addr)
1348    {
1349      int a1_src_scope = get_scope (&a1->source_addr);
1350      int a2_src_scope = get_scope (&a2->source_addr);
1351
1352      if (a1_dst_scope == a1_src_scope && a2_dst_scope != a2_src_scope)
1353        return -1;
1354      if (a1_dst_scope != a1_src_scope && a2_dst_scope == a2_src_scope)
1355        return 1;
1356    }
1357
1358
1359  /* Rule 3: Avoid deprecated addresses.
1360     That's something only the kernel could decide.  */
1361
1362  /* Rule 4: Prefer home addresses.
1363     Another thing only the kernel can decide.  */
1364
1365  /* Rule 5: Prefer matching label.  */
1366  if (a1->got_source_addr)
1367    {
1368      int a1_dst_label
1369        = get_label ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1370      int a1_src_label = get_label (&a1->source_addr);
1371
1372      int a2_dst_label
1373        = get_label ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1374      int a2_src_label = get_label (&a2->source_addr);
1375
1376      if (a1_dst_label == a1_src_label && a2_dst_label != a2_src_label)
1377        return -1;
1378      if (a1_dst_label != a1_src_label && a2_dst_label == a2_src_label)
1379        return 1;
1380    }
1381
1382
1383  /* Rule 6: Prefer higher precedence.  */
1384  int a1_prec
1385    = get_precedence ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1386  int a2_prec
1387    = get_precedence ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1388
1389  if (a1_prec > a2_prec)
1390    return -1;
1391  if (a1_prec < a2_prec)
1392    return 1;
1393
1394
1395  /* Rule 7: Prefer native transport.
1396     XXX How to recognize tunnels?  */
1397
1398
1399  /* Rule 8: Prefer smaller scope.  */
1400  if (a1_dst_scope < a2_dst_scope)
1401    return -1;
1402  if (a1_dst_scope > a2_dst_scope)
1403    return 1;
1404
1405
1406  /* Rule 9: Use longest matching prefix.  */
1407  if (a1->got_source_addr
1408      && a1->dest_addr->ai_family == a2->dest_addr->ai_family)
1409    {
1410      int bit1 = 0;
1411      int bit2 = 0;
1412
1413      if (a1->dest_addr->ai_family == PF_INET)
1414        {
1415          assert (a1->source_addr.ss_family == PF_INET);
1416          assert (a2->source_addr.ss_family == PF_INET);
1417
1418          struct sockaddr_in *in1_dst;
1419          struct sockaddr_in *in1_src;
1420          struct sockaddr_in *in2_dst;
1421          struct sockaddr_in *in2_src;
1422
1423          in1_dst = (struct sockaddr_in *) a1->dest_addr->ai_addr;
1424          in1_src = (struct sockaddr_in *) &a1->source_addr;
1425          in2_dst = (struct sockaddr_in *) a2->dest_addr->ai_addr;
1426          in2_src = (struct sockaddr_in *) &a2->source_addr;
1427
1428          bit1 = ffs (in1_dst->sin_addr.s_addr ^ in1_src->sin_addr.s_addr);
1429          bit2 = ffs (in2_dst->sin_addr.s_addr ^ in2_src->sin_addr.s_addr);
1430        }
1431      else if (a1->dest_addr->ai_family == PF_INET6)
1432        {
1433          assert (a1->source_addr.ss_family == PF_INET6);
1434          assert (a2->source_addr.ss_family == PF_INET6);
1435
1436          struct sockaddr_in6 *in1_dst;
1437          struct sockaddr_in6 *in1_src;
1438          struct sockaddr_in6 *in2_dst;
1439          struct sockaddr_in6 *in2_src;
1440
1441          in1_dst = (struct sockaddr_in6 *) a1->dest_addr->ai_addr;
1442          in1_src = (struct sockaddr_in6 *) &a1->source_addr;
1443          in2_dst = (struct sockaddr_in6 *) a2->dest_addr->ai_addr;
1444          in2_src = (struct sockaddr_in6 *) &a2->source_addr;
1445
1446          int i;
1447          for (i = 0; i < 4; ++i)
1448            if (in1_dst->sin6_addr.s6_addr32[i]
1449                != in1_src->sin6_addr.s6_addr32[i]
1450                || (in2_dst->sin6_addr.s6_addr32[i]
1451                    != in2_src->sin6_addr.s6_addr32[i]))
1452              break;
1453
1454          if (i < 4)
1455            {
1456              bit1 = ffs (in1_dst->sin6_addr.s6_addr32[i]
1457                          ^ in1_src->sin6_addr.s6_addr32[i]);
1458              bit2 = ffs (in2_dst->sin6_addr.s6_addr32[i]
1459                          ^ in2_src->sin6_addr.s6_addr32[i]);
1460            }
1461        }
1462
1463      if (bit1 > bit2)
1464        return -1;
1465      if (bit1 < bit2)
1466        return 1;
1467    }
1468
1469
1470  /* Rule 10: Otherwise, leave the order unchanged.  */
1471  return 0;
1472}
1473
1474
1475int
1476getaddrinfo (const char *__restrict name, const char *__restrict service,
1477             const struct addrinfo *__restrict hints,
1478             struct addrinfo **__restrict pai)
1479{
1480  int i = 0, j = 0, last_i = 0;
1481  int nresults = 0;
1482  struct addrinfo *p = NULL, **end;
1483  struct gaih *g = gaih, *pg = NULL;
1484  struct gaih_service gaih_service, *pservice;
1485  struct addrinfo local_hints;
1486
1487  if (name != NULL && name[0] == '*' && name[1] == 0)
1488    name = NULL;
1489
1490  if (service != NULL && service[0] == '*' && service[1] == 0)
1491    service = NULL;
1492
1493  if (name == NULL && service == NULL)
1494    return EAI_NONAME;
1495
1496  if (hints == NULL)
1497    hints = &default_hints;
1498
1499  if (hints->ai_flags
1500      & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|AI_ADDRCONFIG|AI_V4MAPPED
1501#ifdef HAVE_LIBIDN
1502          |AI_IDN|AI_CANONIDN|AI_IDN_ALLOW_UNASSIGNED
1503          |AI_IDN_USE_STD3_ASCII_RULES
1504#endif
1505          |AI_NUMERICSERV|AI_ALL))
1506    return EAI_BADFLAGS;
1507
1508  if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
1509    return EAI_BADFLAGS;
1510
1511  if (hints->ai_flags & AI_ADDRCONFIG)
1512    {
1513      /* Determine whether we have IPv4 or IPv6 interfaces or both.
1514         We cannot cache the results since new interfaces could be
1515         added at any time.  */
1516      bool seen_ipv4;
1517      bool seen_ipv6;
1518      __check_pf (&seen_ipv4, &seen_ipv6);
1519
1520      /* Now make a decision on what we return, if anything.  */
1521      if (hints->ai_family == PF_UNSPEC && (seen_ipv4 || seen_ipv6))
1522        {
1523          /* If we haven't seen both IPv4 and IPv6 interfaces we can
1524             narrow down the search.  */
1525          if (! seen_ipv4 || ! seen_ipv6)
1526            {
1527              local_hints = *hints;
1528              local_hints.ai_family = seen_ipv4 ? PF_INET : PF_INET6;
1529              hints = &local_hints;
1530            }
1531        }
1532      else if ((hints->ai_family == PF_INET && ! seen_ipv4)
1533               || (hints->ai_family == PF_INET6 && ! seen_ipv6))
1534        /* We cannot possibly return a valid answer.  */
1535        return EAI_NONAME;
1536    }
1537
1538  if (service && service[0])
1539    {
1540      char *c;
1541      gaih_service.name = service;
1542      gaih_service.num = strtoul (gaih_service.name, &c, 10);
1543      if (*c != '\0')
1544        {
1545          if (hints->ai_flags & AI_NUMERICSERV)
1546            return EAI_NONAME;
1547
1548          gaih_service.num = -1;
1549        }
1550
1551      pservice = &gaih_service;
1552    }
1553  else
1554    pservice = NULL;
1555
1556  if (pai)
1557    end = &p;
1558  else
1559    end = NULL;
1560
1561  while (g->gaih)
1562    {
1563      if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
1564        {
1565          j++;
1566          if (pg == NULL || pg->gaih != g->gaih)
1567            {
1568              pg = g;
1569              i = g->gaih (name, pservice, hints, end);
1570              if (i != 0)
1571                {
1572                  /* EAI_NODATA is a more specific result as it says that
1573                     we found a result but it is not usable.  */
1574                  if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA))
1575                    last_i = i;
1576
1577                  if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
1578                    {
1579                      ++g;
1580                      continue;
1581                    }
1582
1583                  freeaddrinfo (p);
1584
1585                  return -(i & GAIH_EAI);
1586                }
1587              if (end)
1588                while (*end)
1589                  {
1590                    end = &((*end)->ai_next);
1591                    ++nresults;
1592                  }
1593            }
1594        }
1595      ++g;
1596    }
1597
1598  if (j == 0)
1599    return EAI_FAMILY;
1600
1601  if (nresults > 1)
1602    {
1603      /* Sort results according to RFC 3484.  */
1604      struct sort_result results[nresults];
1605      struct addrinfo *q;
1606      struct addrinfo *last = NULL;
1607      char *canonname = NULL;
1608
1609      for (i = 0, q = p; q != NULL; ++i, last = q, q = q->ai_next)
1610        {
1611          results[i].dest_addr = q;
1612          results[i].got_source_addr = false;
1613
1614          /* If we just looked up the address for a different
1615             protocol, reuse the result.  */
1616          if (last != NULL && last->ai_addrlen == q->ai_addrlen
1617              && memcmp (last->ai_addr, q->ai_addr, q->ai_addrlen) == 0)
1618            {
1619              memcpy (&results[i].source_addr, &results[i - 1].source_addr,
1620                      results[i - 1].source_addr_len);
1621              results[i].source_addr_len = results[i - 1].source_addr_len;
1622              results[i].got_source_addr = results[i - 1].got_source_addr;
1623            }
1624          else
1625            {
1626              /* We overwrite the type with SOCK_DGRAM since we do not
1627                 want connect() to connect to the other side.  If we
1628                 cannot determine the source address remember this
1629                 fact.  */
1630              int fd = socket (q->ai_family, SOCK_DGRAM, IPPROTO_IP);
1631              socklen_t sl = sizeof (results[i].source_addr);
1632              if (fd != -1
1633                  && connect (fd, q->ai_addr, q->ai_addrlen) == 0
1634                  && getsockname (fd,
1635                                    (struct sockaddr *) &results[i].source_addr,
1636                                    &sl) == 0)
1637                {
1638                  results[i].source_addr_len = sl;
1639                  results[i].got_source_addr = true;
1640                }
1641              else
1642                /* Just make sure that if we have to process the same
1643                   address again we do not copy any memory.  */
1644                results[i].source_addr_len = 0;
1645
1646              if (fd != -1)
1647                close_not_cancel_no_status (fd);
1648            }
1649
1650          /* Remember the canonical name.  */
1651          if (q->ai_canonname != NULL)
1652            {
1653              assert (canonname == NULL);
1654              canonname = q->ai_canonname;
1655              q->ai_canonname = NULL;
1656            }
1657        }
1658
1659      /* We got all the source addresses we can get, now sort using
1660         the information.  */
1661      qsort (results, nresults, sizeof (results[0]), rfc3484_sort);
1662
1663      /* Queue the results up as they come out of sorting.  */
1664      q = p = results[0].dest_addr;
1665      for (i = 1; i < nresults; ++i)
1666        q = q->ai_next = results[i].dest_addr;
1667      q->ai_next = NULL;
1668
1669      /* Fill in the canonical name into the new first entry.  */
1670      p->ai_canonname = canonname;
1671    }
1672
1673  if (p)
1674    {
1675      *pai = p;
1676      return 0;
1677    }
1678
1679  if (pai == NULL && last_i == 0)
1680    return 0;
1681
1682  return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
1683}
1684libc_hidden_def (getaddrinfo)
1685
1686static_link_warning (getaddrinfo)
1687
1688void
1689freeaddrinfo (struct addrinfo *ai)
1690{
1691  struct addrinfo *p;
1692
1693  while (ai != NULL)
1694    {
1695      p = ai;
1696      ai = ai->ai_next;
1697      free (p->ai_canonname);
1698      free (p);
1699    }
1700}
1701libc_hidden_def (freeaddrinfo)
Note: See TracBrowser for help on using the repository browser.