1 /* The Inner Net License, Version 2.00
3 The author(s) grant permission for redistribution and use in source and
4 binary forms, with or without modification, of the software and documentation
5 provided that the following conditions are met:
7 0. If you receive a version of the software that is specifically labelled
8 as not being for redistribution (check the version message and/or README),
9 you are not permitted to redistribute that version of the software in any
11 1. All terms of the all other applicable copyrights and licenses must be
13 2. Redistributions of source code must retain the authors' copyright
14 notice(s), this list of conditions, and the following disclaimer.
15 3. Redistributions in binary form must reproduce the authors' copyright
16 notice(s), this list of conditions, and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18 4. [The copyright holder has authorized the removal of this clause.]
19 5. Neither the name(s) of the author(s) nor the names of its contributors
20 may be used to endorse or promote products derived from this software
21 without specific prior written permission.
23 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
24 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
27 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 If these license terms cause you a real problem, contact the author. */
36 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
46 #include <stdio_ext.h>
49 #include <arpa/inet.h>
51 #include <netinet/in.h>
52 #include <sys/socket.h>
54 #include <sys/types.h>
56 #include <sys/utsname.h>
59 #include <bits/libc-lock.h>
60 #include <not-cancel.h>
61 #include <nscd/nscd-client.h>
62 #include <nscd/nscd_proto.h>
65 extern int __idna_to_ascii_lz (const char *input
, char **output
, int flags
);
66 extern int __idna_to_unicode_lzlz (const char *input
, char **output
,
68 # include <libidn/idna.h>
71 #define GAIH_OKIFUNSPEC 0x0100
72 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
75 # define UNIX_PATH_MAX 108
86 struct gaih_servtuple
*next
;
92 static const struct gaih_servtuple nullserv
;
96 struct gaih_addrtuple
*next
;
103 struct gaih_typeproto
111 /* Values for `protoflag'. */
112 #define GAI_PROTO_NOSERVICE 1
113 #define GAI_PROTO_PROTOANY 2
115 static const struct gaih_typeproto gaih_inet_typeproto
[] =
118 { SOCK_STREAM
, IPPROTO_TCP
, "tcp", 0 },
119 { SOCK_DGRAM
, IPPROTO_UDP
, "udp", 0 },
120 { SOCK_RAW
, 0, "raw", GAI_PROTO_PROTOANY
|GAI_PROTO_NOSERVICE
},
127 int (*gaih
)(const char *name
, const struct gaih_service
*service
,
128 const struct addrinfo
*req
, struct addrinfo
**pai
,
129 unsigned int *naddrs
);
132 static const struct addrinfo default_hints
=
134 .ai_flags
= AI_DEFAULT
,
135 .ai_family
= PF_UNSPEC
,
140 .ai_canonname
= NULL
,
146 /* Using Unix sockets this way is a security risk. */
148 gaih_local (const char *name
, const struct gaih_service
*service
,
149 const struct addrinfo
*req
, struct addrinfo
**pai
)
151 struct utsname utsname
;
153 if ((name
!= NULL
) && (req
->ai_flags
& AI_NUMERICHOST
))
154 return GAIH_OKIFUNSPEC
| -EAI_NONAME
;
156 if ((name
!= NULL
) || (req
->ai_flags
& AI_CANONNAME
))
157 if (uname (&utsname
) < 0)
162 if (strcmp(name
, "localhost") &&
163 strcmp(name
, "local") &&
164 strcmp(name
, "unix") &&
165 strcmp(name
, utsname
.nodename
))
166 return GAIH_OKIFUNSPEC
| -EAI_NONAME
;
169 if (req
->ai_protocol
|| req
->ai_socktype
)
171 const struct gaih_typeproto
*tp
= gaih_inet_typeproto
+ 1;
174 && ((tp
->protoflag
& GAI_PROTO_NOSERVICE
) != 0
175 || (req
->ai_socktype
!= 0 && req
->ai_socktype
!= tp
->socktype
)
176 || (req
->ai_protocol
!= 0
177 && !(tp
->protoflag
& GAI_PROTO_PROTOANY
)
178 && req
->ai_protocol
!= tp
->protocol
)))
183 if (req
->ai_socktype
)
184 return GAIH_OKIFUNSPEC
| -EAI_SOCKTYPE
;
186 return GAIH_OKIFUNSPEC
| -EAI_SERVICE
;
190 *pai
= malloc (sizeof (struct addrinfo
) + sizeof (struct sockaddr_un
)
191 + ((req
->ai_flags
& AI_CANONNAME
)
192 ? (strlen(utsname
.nodename
) + 1): 0));
196 (*pai
)->ai_next
= NULL
;
197 (*pai
)->ai_flags
= req
->ai_flags
;
198 (*pai
)->ai_family
= AF_LOCAL
;
199 (*pai
)->ai_socktype
= req
->ai_socktype
? req
->ai_socktype
: SOCK_STREAM
;
200 (*pai
)->ai_protocol
= req
->ai_protocol
;
201 (*pai
)->ai_addrlen
= sizeof (struct sockaddr_un
);
202 (*pai
)->ai_addr
= (void *) (*pai
) + sizeof (struct addrinfo
);
205 ((struct sockaddr_un
*) (*pai
)->ai_addr
)->sun_len
=
206 sizeof (struct sockaddr_un
);
207 #endif /* _HAVE_SA_LEN */
209 ((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_family
= AF_LOCAL
;
210 memset(((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_path
, 0, UNIX_PATH_MAX
);
214 struct sockaddr_un
*sunp
= (struct sockaddr_un
*) (*pai
)->ai_addr
;
216 if (strchr (service
->name
, '/') != NULL
)
218 if (strlen (service
->name
) >= sizeof (sunp
->sun_path
))
219 return GAIH_OKIFUNSPEC
| -EAI_SERVICE
;
221 strcpy (sunp
->sun_path
, service
->name
);
225 if (strlen (P_tmpdir
"/") + 1 + strlen (service
->name
) >=
226 sizeof (sunp
->sun_path
))
227 return GAIH_OKIFUNSPEC
| -EAI_SERVICE
;
229 __stpcpy (__stpcpy (sunp
->sun_path
, P_tmpdir
"/"), service
->name
);
234 /* This is a dangerous use of the interface since there is a time
235 window between the test for the file and the actual creation
236 (done by the caller) in which a file with the same name could
238 char *buf
= ((struct sockaddr_un
*) (*pai
)->ai_addr
)->sun_path
;
240 if (__builtin_expect (__path_search (buf
, L_tmpnam
, NULL
, NULL
, 0),
242 || __builtin_expect (__gen_tempname (buf
, __GT_NOCREATE
), 0) != 0)
246 if (req
->ai_flags
& AI_CANONNAME
)
247 (*pai
)->ai_canonname
= strcpy ((char *) *pai
+ sizeof (struct addrinfo
)
248 + sizeof (struct sockaddr_un
),
251 (*pai
)->ai_canonname
= NULL
;
258 gaih_inet_serv (const char *servicename
, const struct gaih_typeproto
*tp
,
259 const struct addrinfo
*req
, struct gaih_servtuple
*st
)
262 size_t tmpbuflen
= 1024;
269 tmpbuf
= __alloca (tmpbuflen
);
271 r
= __getservbyname_r (servicename
, tp
->name
, &ts
, tmpbuf
, tmpbuflen
,
273 if (r
!= 0 || s
== NULL
)
278 return GAIH_OKIFUNSPEC
| -EAI_SERVICE
;
284 st
->socktype
= tp
->socktype
;
285 st
->protocol
= ((tp
->protoflag
& GAI_PROTO_PROTOANY
)
286 ? req
->ai_protocol
: tp
->protocol
);
287 st
->port
= s
->s_port
;
292 #define gethosts(_family, _type) \
298 char *localcanon = NULL; \
302 status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf, tmpbuflen, \
303 &rc, &herrno, NULL, &localcanon)); \
304 if (rc != ERANGE || herrno != NETDB_INTERNAL) \
306 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \
308 if (status == NSS_STATUS_SUCCESS && rc == 0) \
314 if (herrno == NETDB_INTERNAL) \
316 __set_h_errno (herrno); \
317 return -EAI_SYSTEM; \
319 if (herrno == TRY_AGAIN) \
320 no_data = EAI_AGAIN; \
322 no_data = herrno == NO_DATA; \
324 else if (h != NULL) \
326 for (i = 0; h->h_addr_list[i]; i++) \
330 *pat = __alloca (sizeof (struct gaih_addrtuple)); \
331 (*pat)->scopeid = 0; \
333 uint32_t *addr = (*pat)->addr; \
334 (*pat)->next = NULL; \
335 (*pat)->name = i == 0 ? strdupa (h->h_name) : NULL; \
336 if (_family == AF_INET && req->ai_family == AF_INET6) \
338 (*pat)->family = AF_INET6; \
339 addr[3] = *(uint32_t *) h->h_addr_list[i]; \
340 addr[2] = htonl (0xffff); \
346 (*pat)->family = _family; \
347 memcpy (addr, h->h_addr_list[i], sizeof(_type)); \
349 pat = &((*pat)->next); \
352 if (localcanon != NULL && canon == NULL) \
353 canon = strdupa (localcanon); \
355 if (_family == AF_INET6 && i > 0) \
361 typedef enum nss_status (*nss_gethostbyname3_r
)
362 (const char *name
, int af
, struct hostent
*host
,
363 char *buffer
, size_t buflen
, int *errnop
,
364 int *h_errnop
, int32_t *ttlp
, char **canonp
);
365 typedef enum nss_status (*nss_getcanonname_r
)
366 (const char *name
, char *buffer
, size_t buflen
, char **result
,
367 int *errnop
, int *h_errnop
);
368 extern service_user
*__nss_hosts_database attribute_hidden
;
372 gaih_inet (const char *name
, const struct gaih_service
*service
,
373 const struct addrinfo
*req
, struct addrinfo
**pai
,
374 unsigned int *naddrs
)
376 const struct gaih_typeproto
*tp
= gaih_inet_typeproto
;
377 struct gaih_servtuple
*st
= (struct gaih_servtuple
*) &nullserv
;
378 struct gaih_addrtuple
*at
= NULL
;
380 bool got_ipv6
= false;
381 const char *canon
= NULL
;
382 const char *orig_name
= name
;
384 if (req
->ai_protocol
|| req
->ai_socktype
)
389 && ((req
->ai_socktype
!= 0 && req
->ai_socktype
!= tp
->socktype
)
390 || (req
->ai_protocol
!= 0
391 && !(tp
->protoflag
& GAI_PROTO_PROTOANY
)
392 && req
->ai_protocol
!= tp
->protocol
)))
397 if (req
->ai_socktype
)
398 return GAIH_OKIFUNSPEC
| -EAI_SOCKTYPE
;
400 return GAIH_OKIFUNSPEC
| -EAI_SERVICE
;
407 if ((tp
->protoflag
& GAI_PROTO_NOSERVICE
) != 0)
408 return GAIH_OKIFUNSPEC
| -EAI_SERVICE
;
410 if (service
->num
< 0)
414 st
= (struct gaih_servtuple
*)
415 __alloca (sizeof (struct gaih_servtuple
));
417 if ((rc
= gaih_inet_serv (service
->name
, tp
, req
, st
)))
422 struct gaih_servtuple
**pst
= &st
;
423 for (tp
++; tp
->name
[0]; tp
++)
425 struct gaih_servtuple
*newp
;
427 if ((tp
->protoflag
& GAI_PROTO_NOSERVICE
) != 0)
430 if (req
->ai_socktype
!= 0
431 && req
->ai_socktype
!= tp
->socktype
)
433 if (req
->ai_protocol
!= 0
434 && !(tp
->protoflag
& GAI_PROTO_PROTOANY
)
435 && req
->ai_protocol
!= tp
->protocol
)
438 newp
= (struct gaih_servtuple
*)
439 __alloca (sizeof (struct gaih_servtuple
));
441 if ((rc
= gaih_inet_serv (service
->name
, tp
, req
, newp
)))
443 if (rc
& GAIH_OKIFUNSPEC
)
451 if (st
== (struct gaih_servtuple
*) &nullserv
)
452 return GAIH_OKIFUNSPEC
| -EAI_SERVICE
;
457 port
= htons (service
->num
);
465 if (req
->ai_socktype
|| req
->ai_protocol
)
467 st
= __alloca (sizeof (struct gaih_servtuple
));
469 st
->socktype
= tp
->socktype
;
470 st
->protocol
= ((tp
->protoflag
& GAI_PROTO_PROTOANY
)
471 ? req
->ai_protocol
: tp
->protocol
);
476 /* Neither socket type nor protocol is set. Return all socket types
478 struct gaih_servtuple
**lastp
= &st
;
479 for (++tp
; tp
->name
[0]; ++tp
)
481 struct gaih_servtuple
*newp
;
483 newp
= __alloca (sizeof (struct gaih_servtuple
));
485 newp
->socktype
= tp
->socktype
;
486 newp
->protocol
= tp
->protocol
;
497 at
= __alloca (sizeof (struct gaih_addrtuple
));
499 at
->family
= AF_UNSPEC
;
504 if (req
->ai_flags
& AI_IDN
)
507 if (req
->ai_flags
& AI_IDN_ALLOW_UNASSIGNED
)
508 idn_flags
|= IDNA_ALLOW_UNASSIGNED
;
509 if (req
->ai_flags
& AI_IDN_USE_STD3_ASCII_RULES
)
510 idn_flags
|= IDNA_USE_STD3_ASCII_RULES
;
513 rc
= __idna_to_ascii_lz (name
, &p
, idn_flags
);
514 if (rc
!= IDNA_SUCCESS
)
516 if (rc
== IDNA_MALLOC_ERROR
)
518 if (rc
== IDNA_DLOPEN_ERROR
)
520 return -EAI_IDN_ENCODE
;
522 /* In case the output string is the same as the input string
523 no new string has been allocated. */
532 if (__inet_aton (name
, (struct in_addr
*) at
->addr
) != 0)
534 if (req
->ai_family
== AF_UNSPEC
|| req
->ai_family
== AF_INET
)
535 at
->family
= AF_INET
;
536 else if (req
->ai_family
== AF_INET6
&& (req
->ai_flags
& AI_V4MAPPED
))
538 at
->addr
[3] = at
->addr
[0];
539 at
->addr
[2] = htonl (0xffff);
542 at
->family
= AF_INET6
;
545 return -EAI_ADDRFAMILY
;
547 if (req
->ai_flags
& AI_CANONNAME
)
550 else if (at
->family
== AF_UNSPEC
)
552 char *namebuf
= (char *) name
;
553 char *scope_delim
= strchr (name
, SCOPE_DELIMITER
);
555 if (__builtin_expect (scope_delim
!= NULL
, 0))
557 namebuf
= alloca (scope_delim
- name
+ 1);
558 *((char *) __mempcpy (namebuf
, name
, scope_delim
- name
)) = '\0';
561 if (inet_pton (AF_INET6
, namebuf
, at
->addr
) > 0)
563 if (req
->ai_family
== AF_UNSPEC
|| req
->ai_family
== AF_INET6
)
564 at
->family
= AF_INET6
;
565 else if (req
->ai_family
== AF_INET
566 && IN6_IS_ADDR_V4MAPPED (at
->addr
))
568 at
->addr
[0] = at
->addr
[3];
569 at
->family
= AF_INET
;
572 return -EAI_ADDRFAMILY
;
574 if (scope_delim
!= NULL
)
576 int try_numericscope
= 0;
577 if (IN6_IS_ADDR_LINKLOCAL (at
->addr
)
578 || IN6_IS_ADDR_MC_LINKLOCAL (at
->addr
))
580 at
->scopeid
= if_nametoindex (scope_delim
+ 1);
581 if (at
->scopeid
== 0)
582 try_numericscope
= 1;
585 try_numericscope
= 1;
587 if (try_numericscope
!= 0)
590 assert (sizeof (uint32_t) <= sizeof (unsigned long));
591 at
->scopeid
= (uint32_t) strtoul (scope_delim
+ 1, &end
,
594 return GAIH_OKIFUNSPEC
| -EAI_NONAME
;
598 if (req
->ai_flags
& AI_CANONNAME
)
603 if (at
->family
== AF_UNSPEC
&& (req
->ai_flags
& AI_NUMERICHOST
) == 0)
605 struct gaih_addrtuple
**pat
= &at
;
607 int no_inet6_data
= 0;
608 service_user
*nip
= NULL
;
609 enum nss_status inet6_status
= NSS_STATUS_UNAVAIL
;
610 enum nss_status status
= NSS_STATUS_UNAVAIL
;
614 /* If we do not have to look for IPv4 and IPv6 together, use
615 the simple, old functions. */
616 if (req
->ai_family
== AF_INET
617 || (req
->ai_family
== AF_INET6
618 && ((req
->ai_flags
& AI_V4MAPPED
) == 0
619 || (req
->ai_flags
& AI_ALL
) == 0)))
621 int family
= req
->ai_family
;
622 size_t tmpbuflen
= 512;
623 char *tmpbuf
= alloca (tmpbuflen
);
632 rc
= __gethostbyname2_r (name
, family
, &th
, tmpbuf
,
633 tmpbuflen
, &h
, &herrno
);
634 if (rc
!= ERANGE
|| herrno
!= NETDB_INTERNAL
)
636 tmpbuf
= extend_alloca (tmpbuf
, tmpbuflen
, 2 * tmpbuflen
);
643 if (req
->ai_family
== AF_INET6
644 && (req
->ai_flags
& AI_V4MAPPED
)
645 && family
== AF_INET6
)
647 /* Try again, this time looking for IPv4
655 /* We found data, now convert it into the list. */
656 for (int i
= 0; h
->h_addr_list
[i
]; ++i
)
660 *pat
= __alloca (sizeof (struct gaih_addrtuple
));
664 (*pat
)->family
= req
->ai_family
;
665 if (family
== req
->ai_family
)
666 memcpy ((*pat
)->addr
, h
->h_addr_list
[i
],
670 uint32_t *addr
= (uint32_t *) (*pat
)->addr
;
671 addr
[3] = *(uint32_t *) h
->h_addr_list
[i
];
672 addr
[2] = htonl (0xffff);
676 pat
= &((*pat
)->next
);
682 if (herrno
== NETDB_INTERNAL
)
684 __set_h_errno (herrno
);
687 if (herrno
== TRY_AGAIN
)
691 /* We made requests but they turned out no data.
692 The name is known, though. */
693 return GAIH_OKIFUNSPEC
| -EAI_NODATA
;
700 if (__nss_not_use_nscd_hosts
> 0
701 && ++__nss_not_use_nscd_hosts
> NSS_NSCD_RETRY
)
702 __nss_not_use_nscd_hosts
= 0;
704 if (!__nss_not_use_nscd_hosts
)
706 /* Try to use nscd. */
707 struct nscd_ai_result
*air
= NULL
;
709 int err
= __nscd_getai (name
, &air
, &herrno
);
712 /* Transform into gaih_addrtuple list. */
713 bool added_canon
= (req
->ai_flags
& AI_CANONNAME
) == 0;
714 char *addrs
= air
->addrs
;
716 for (int i
= 0; i
< air
->naddrs
; ++i
)
718 socklen_t size
= (air
->family
[i
] == AF_INET
719 ? INADDRSZ
: IN6ADDRSZ
);
722 *pat
= __alloca (sizeof (struct gaih_addrtuple
));
725 uint32_t *pataddr
= (*pat
)->addr
;
727 if (added_canon
|| air
->canon
== NULL
)
730 canon
= (*pat
)->name
= strdupa (air
->canon
);
732 if (air
->family
[i
] == AF_INET
733 && req
->ai_family
== AF_INET6
734 && (req
->ai_flags
& AI_V4MAPPED
))
736 (*pat
)->family
= AF_INET6
;
737 pataddr
[3] = *(uint32_t *) addrs
;
738 pataddr
[2] = htonl (0xffff);
741 pat
= &((*pat
)->next
);
744 else if (req
->ai_family
== AF_UNSPEC
745 || air
->family
[i
] == req
->ai_family
)
747 (*pat
)->family
= air
->family
[i
];
748 memcpy (pataddr
, addrs
, size
);
749 pat
= &((*pat
)->next
);
751 if (air
->family
[i
] == AF_INET6
)
759 if (at
->family
== AF_UNSPEC
)
760 return GAIH_OKIFUNSPEC
| -EAI_NONAME
;
764 else if (err
!= 0 && __nss_not_use_nscd_hosts
== 0)
766 if (herrno
== NETDB_INTERNAL
&& errno
== ENOMEM
)
768 if (herrno
== TRY_AGAIN
)
775 if (__nss_hosts_database
!= NULL
)
778 nip
= __nss_hosts_database
;
781 no_more
= __nss_database_lookup ("hosts", NULL
,
782 "dns [!UNAVAIL=return] files",
785 if (__res_maybe_init (&_res
, 0) == -1)
788 /* If we are looking for both IPv4 and IPv6 address we don't
789 want the lookup functions to automatically promote IPv4
790 addresses to IPv6 addresses. Currently this is decided
791 by setting the RES_USE_INET6 bit in _res.options. */
792 old_res_options
= _res
.options
;
793 _res
.options
&= ~RES_USE_INET6
;
795 size_t tmpbuflen
= 512;
796 char *tmpbuf
= alloca (tmpbuflen
);
800 nss_gethostbyname3_r fct
= NULL
;
801 if (req
->ai_flags
& AI_CANONNAME
)
802 /* No need to use this function if we do not look for
803 the canonical name. The function does not exist in
804 all NSS modules and therefore the lookup would
806 fct
= __nss_lookup_function (nip
, "gethostbyname3_r");
808 /* We are cheating here. The gethostbyname2_r function does
809 not have the same interface as gethostbyname3_r but the
810 extra arguments the latter takes are added at the end.
811 So the gethostbyname2_r code will just ignore them. */
812 fct
= __nss_lookup_function (nip
, "gethostbyname2_r");
816 if (req
->ai_family
== AF_INET6
817 || req
->ai_family
== AF_UNSPEC
)
819 gethosts (AF_INET6
, struct in6_addr
);
820 no_inet6_data
= no_data
;
821 inet6_status
= status
;
823 if (req
->ai_family
== AF_INET
824 || req
->ai_family
== AF_UNSPEC
825 || (req
->ai_family
== AF_INET6
826 && (req
->ai_flags
& AI_V4MAPPED
)
827 /* Avoid generating the mapped addresses if we
828 know we are not going to need them. */
829 && ((req
->ai_flags
& AI_ALL
) || !got_ipv6
)))
831 gethosts (AF_INET
, struct in_addr
);
833 if (req
->ai_family
== AF_INET
)
835 no_inet6_data
= no_data
;
836 inet6_status
= status
;
840 /* If we found one address for AF_INET or AF_INET6,
841 don't continue the search. */
842 if (inet6_status
== NSS_STATUS_SUCCESS
843 || status
== NSS_STATUS_SUCCESS
)
845 if ((req
->ai_flags
& AI_CANONNAME
) != 0 && canon
== NULL
)
847 /* If we need the canonical name, get it
848 from the same service as the result. */
849 nss_getcanonname_r cfct
;
852 cfct
= __nss_lookup_function (nip
, "getcanonname_r");
855 const size_t max_fqdn_len
= 256;
856 char *buf
= alloca (max_fqdn_len
);
859 if (DL_CALL_FCT (cfct
, (at
->name
?: name
, buf
,
860 max_fqdn_len
, &s
, &rc
,
862 == NSS_STATUS_SUCCESS
)
865 /* Set to name now to avoid using
874 /* We can have different states for AF_INET and
875 AF_INET6. Try to find a useful one for both. */
876 if (inet6_status
== NSS_STATUS_TRYAGAIN
)
877 status
= NSS_STATUS_TRYAGAIN
;
878 else if (status
== NSS_STATUS_UNAVAIL
879 && inet6_status
!= NSS_STATUS_UNAVAIL
)
880 status
= inet6_status
;
883 if (nss_next_action (nip
, status
) == NSS_ACTION_RETURN
)
886 if (nip
->next
== NULL
)
892 _res
.options
= old_res_options
;
894 if (no_data
!= 0 && no_inet6_data
!= 0)
896 /* If both requests timed out report this. */
897 if (no_data
== EAI_AGAIN
&& no_inet6_data
== EAI_AGAIN
)
900 /* We made requests but they turned out no data. The name
902 return GAIH_OKIFUNSPEC
| -EAI_NODATA
;
907 if (at
->family
== AF_UNSPEC
)
908 return GAIH_OKIFUNSPEC
| -EAI_NONAME
;
912 struct gaih_addrtuple
*atr
;
913 atr
= at
= __alloca (sizeof (struct gaih_addrtuple
));
914 memset (at
, '\0', sizeof (struct gaih_addrtuple
));
916 if (req
->ai_family
== AF_UNSPEC
)
918 at
->next
= __alloca (sizeof (struct gaih_addrtuple
));
919 memset (at
->next
, '\0', sizeof (struct gaih_addrtuple
));
922 if (req
->ai_family
== AF_UNSPEC
|| req
->ai_family
== AF_INET6
)
924 at
->family
= AF_INET6
;
925 if ((req
->ai_flags
& AI_PASSIVE
) == 0)
926 memcpy (at
->addr
, &in6addr_loopback
, sizeof (struct in6_addr
));
930 if (req
->ai_family
== AF_UNSPEC
|| req
->ai_family
== AF_INET
)
932 atr
->family
= AF_INET
;
933 if ((req
->ai_flags
& AI_PASSIVE
) == 0)
934 atr
->addr
[0] = htonl (INADDR_LOOPBACK
);
942 struct gaih_servtuple
*st2
;
943 struct gaih_addrtuple
*at2
= at
;
948 buffer is the size of an unformatted IPv6 address in printable format.
952 /* Only the first entry gets the canonical name. */
953 if (at2
== at
&& (req
->ai_flags
& AI_CANONNAME
) != 0)
957 struct hostent
*h
= NULL
;
960 size_t tmpbuflen
= 512;
965 tmpbuf
= extend_alloca (tmpbuf
, tmpbuflen
, tmpbuflen
* 2);
966 rc
= __gethostbyaddr_r (at2
->addr
,
967 ((at2
->family
== AF_INET6
)
968 ? sizeof (struct in6_addr
)
969 : sizeof (struct in_addr
)),
970 at2
->family
, &th
, tmpbuf
,
971 tmpbuflen
, &h
, &herrno
);
973 while (rc
== ERANGE
&& herrno
== NETDB_INTERNAL
);
975 if (rc
!= 0 && herrno
== NETDB_INTERNAL
)
977 __set_h_errno (herrno
);
985 assert (orig_name
!= NULL
);
986 /* If the canonical name cannot be determined, use
987 the passed in string. */
993 if (req
->ai_flags
& AI_CANONIDN
)
996 if (req
->ai_flags
& AI_IDN_ALLOW_UNASSIGNED
)
997 idn_flags
|= IDNA_ALLOW_UNASSIGNED
;
998 if (req
->ai_flags
& AI_IDN_USE_STD3_ASCII_RULES
)
999 idn_flags
|= IDNA_USE_STD3_ASCII_RULES
;
1002 int rc
= __idna_to_unicode_lzlz (canon
, &out
, idn_flags
);
1003 if (rc
!= IDNA_SUCCESS
)
1005 if (rc
== IDNA_MALLOC_ERROR
)
1007 if (rc
== IDNA_DLOPEN_ERROR
)
1009 return -EAI_IDN_ENCODE
;
1011 /* In case the output string is the same as the input
1012 string no new string has been allocated. Otherwise
1023 canon
= strdup (canon
);
1029 family
= at2
->family
;
1030 if (family
== AF_INET6
)
1032 socklen
= sizeof (struct sockaddr_in6
);
1034 /* If we looked up IPv4 mapped address discard them here if
1035 the caller isn't interested in all address and we have
1036 found at least one IPv6 address. */
1038 && (req
->ai_flags
& (AI_V4MAPPED
|AI_ALL
)) == AI_V4MAPPED
1039 && IN6_IS_ADDR_V4MAPPED (at2
->addr
))
1043 socklen
= sizeof (struct sockaddr_in
);
1045 for (st2
= st
; st2
!= NULL
; st2
= st2
->next
)
1047 struct addrinfo
*ai
;
1048 ai
= *pai
= malloc (sizeof (struct addrinfo
) + socklen
);
1051 free ((char *) canon
);
1055 ai
->ai_flags
= req
->ai_flags
;
1056 ai
->ai_family
= family
;
1057 ai
->ai_socktype
= st2
->socktype
;
1058 ai
->ai_protocol
= st2
->protocol
;
1059 ai
->ai_addrlen
= socklen
;
1060 ai
->ai_addr
= (void *) (ai
+ 1);
1062 /* We only add the canonical name once. */
1063 ai
->ai_canonname
= (char *) canon
;
1067 ai
->ai_addr
->sa_len
= socklen
;
1068 #endif /* _HAVE_SA_LEN */
1069 ai
->ai_addr
->sa_family
= family
;
1071 /* In case of an allocation error the list must be NULL
1075 if (family
== AF_INET6
)
1077 struct sockaddr_in6
*sin6p
=
1078 (struct sockaddr_in6
*) ai
->ai_addr
;
1080 sin6p
->sin6_port
= st2
->port
;
1081 sin6p
->sin6_flowinfo
= 0;
1082 memcpy (&sin6p
->sin6_addr
,
1083 at2
->addr
, sizeof (struct in6_addr
));
1084 sin6p
->sin6_scope_id
= at2
->scopeid
;
1088 struct sockaddr_in
*sinp
=
1089 (struct sockaddr_in
*) ai
->ai_addr
;
1090 sinp
->sin_port
= st2
->port
;
1091 memcpy (&sinp
->sin_addr
,
1092 at2
->addr
, sizeof (struct in_addr
));
1093 memset (sinp
->sin_zero
, '\0', sizeof (sinp
->sin_zero
));
1096 pai
= &(ai
->ai_next
);
1109 static const struct gaih gaih
[] =
1111 { PF_INET6
, gaih_inet
},
1112 { PF_INET
, gaih_inet
},
1114 { PF_LOCAL
, gaih_local
},
1122 struct addrinfo
*dest_addr
;
1123 struct sockaddr_storage source_addr
;
1124 uint8_t source_addr_len
;
1125 bool got_source_addr
;
1126 uint8_t source_addr_flags
;
1131 get_scope (const struct sockaddr_storage
*ss
)
1134 if (ss
->ss_family
== PF_INET6
)
1136 const struct sockaddr_in6
*in6
= (const struct sockaddr_in6
*) ss
;
1138 if (! IN6_IS_ADDR_MULTICAST (&in6
->sin6_addr
))
1140 if (IN6_IS_ADDR_LINKLOCAL (&in6
->sin6_addr
))
1142 else if (IN6_IS_ADDR_SITELOCAL (&in6
->sin6_addr
))
1145 /* XXX Is this the correct default behavior? */
1149 scope
= in6
->sin6_addr
.s6_addr
[1] & 0xf;
1151 else if (ss
->ss_family
== PF_INET
)
1153 const struct sockaddr_in
*in
= (const struct sockaddr_in
*) ss
;
1154 const uint8_t *addr
= (const uint8_t *) &in
->sin_addr
;
1156 /* RFC 3484 specifies how to map IPv6 addresses to scopes.
1157 169.254/16 and 127/8 are link-local. */
1158 if ((addr
[0] == 169 && addr
[1] == 254) || addr
[0] == 127)
1160 else if (addr
[0] == 10 || (addr
[0] == 172 && addr
[1] == 16)
1161 || (addr
[0] == 192 && addr
[1] == 168))
1167 /* XXX What is a good default? */
1176 struct in6_addr prefix
;
1182 /* The label table. */
1183 static const struct prefixentry
*labels
;
1185 /* Default labels. */
1186 static const struct prefixentry default_labels
[] =
1188 /* See RFC 3484 for the details. */
1190 = { .u6_addr8
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
1194 = { .u6_addr8
= { 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1195 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
1198 = { .u6_addr8
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
1202 = { .u6_addr8
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1203 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } },
1205 /* The next two entries differ from RFC 3484. We need to treat
1206 IPv6 site-local addresses special because they are never NATed,
1207 unlike site-locale IPv4 addresses. If this would not happen, on
1208 machines which have only IPv4 and IPv6 site-local addresses, the
1209 sorting would prefer the IPv6 site-local addresses, causing
1210 unnecessary delays when trying to connect to a global IPv6 address
1211 through a site-local IPv6 address. */
1213 = { .u6_addr8
= { 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
1217 = { .u6_addr8
= { 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
1221 = { .u6_addr8
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
1227 /* The precedence table. */
1228 static const struct prefixentry
*precedence
;
1230 /* The default precedences. */
1231 static const struct prefixentry default_precedence
[] =
1233 /* See RFC 3484 for the details. */
1235 = { .u6_addr8
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
1239 = { .u6_addr8
= { 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
1243 = { .u6_addr8
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
1247 = { .u6_addr8
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1248 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } },
1251 = { .u6_addr8
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
1258 match_prefix (const struct sockaddr_storage
*ss
,
1259 const struct prefixentry
*list
, int default_val
)
1262 struct sockaddr_in6 in6_mem
;
1263 const struct sockaddr_in6
*in6
;
1265 if (ss
->ss_family
== PF_INET6
)
1266 in6
= (const struct sockaddr_in6
*) ss
;
1267 else if (ss
->ss_family
== PF_INET
)
1269 const struct sockaddr_in
*in
= (const struct sockaddr_in
*) ss
;
1271 /* Convert to IPv6 address. */
1272 in6_mem
.sin6_family
= PF_INET6
;
1273 in6_mem
.sin6_port
= in
->sin_port
;
1274 in6_mem
.sin6_flowinfo
= 0;
1275 if (in
->sin_addr
.s_addr
== htonl (0x7f000001))
1276 in6_mem
.sin6_addr
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
1279 /* Construct a V4-to-6 mapped address. */
1280 memset (&in6_mem
.sin6_addr
, '\0', sizeof (in6_mem
.sin6_addr
));
1281 in6_mem
.sin6_addr
.s6_addr16
[5] = 0xffff;
1282 in6_mem
.sin6_addr
.s6_addr32
[3] = in
->sin_addr
.s_addr
;
1283 in6_mem
.sin6_scope_id
= 0;
1291 for (idx
= 0; ; ++idx
)
1293 unsigned int bits
= list
[idx
].bits
;
1294 const uint8_t *mask
= list
[idx
].prefix
.s6_addr
;
1295 const uint8_t *val
= in6
->sin6_addr
.s6_addr
;
1309 if ((*mask
& (0xff00 >> bits
)) == (*val
& (0xff00 >> bits
)))
1315 return list
[idx
].val
;
1320 get_label (const struct sockaddr_storage
*ss
)
1322 /* XXX What is a good default value? */
1323 return match_prefix (ss
, labels
, INT_MAX
);
1328 get_precedence (const struct sockaddr_storage
*ss
)
1330 /* XXX What is a good default value? */
1331 return match_prefix (ss
, precedence
, 0);
1335 /* Find last bit set in a word. */
1341 for (n
= 0, mask
= 1 << 31; n
< 32; mask
>>= 1, ++n
)
1342 if ((a
& mask
) != 0)
1349 rfc3484_sort (const void *p1
, const void *p2
)
1351 const struct sort_result
*a1
= (const struct sort_result
*) p1
;
1352 const struct sort_result
*a2
= (const struct sort_result
*) p2
;
1354 /* Rule 1: Avoid unusable destinations.
1355 We have the got_source_addr flag set if the destination is reachable. */
1356 if (a1
->got_source_addr
&& ! a2
->got_source_addr
)
1358 if (! a1
->got_source_addr
&& a2
->got_source_addr
)
1362 /* Rule 2: Prefer matching scope. Only interesting if both
1363 destination addresses are IPv6. */
1365 = get_scope ((struct sockaddr_storage
*) a1
->dest_addr
->ai_addr
);
1368 = get_scope ((struct sockaddr_storage
*) a2
->dest_addr
->ai_addr
);
1370 if (a1
->got_source_addr
)
1372 int a1_src_scope
= get_scope (&a1
->source_addr
);
1373 int a2_src_scope
= get_scope (&a2
->source_addr
);
1375 if (a1_dst_scope
== a1_src_scope
&& a2_dst_scope
!= a2_src_scope
)
1377 if (a1_dst_scope
!= a1_src_scope
&& a2_dst_scope
== a2_src_scope
)
1382 /* Rule 3: Avoid deprecated addresses. */
1383 if (a1
->got_source_addr
)
1385 if (!(a1
->source_addr_flags
& in6ai_deprecated
)
1386 && (a2
->source_addr_flags
& in6ai_deprecated
))
1388 if ((a1
->source_addr_flags
& in6ai_deprecated
)
1389 && !(a2
->source_addr_flags
& in6ai_deprecated
))
1393 /* Rule 4: Prefer home addresses. */
1394 if (a1
->got_source_addr
)
1396 if (!(a1
->source_addr_flags
& in6ai_homeaddress
)
1397 && (a2
->source_addr_flags
& in6ai_homeaddress
))
1399 if ((a1
->source_addr_flags
& in6ai_homeaddress
)
1400 && !(a2
->source_addr_flags
& in6ai_homeaddress
))
1404 /* Rule 5: Prefer matching label. */
1405 if (a1
->got_source_addr
)
1408 = get_label ((struct sockaddr_storage
*) a1
->dest_addr
->ai_addr
);
1409 int a1_src_label
= get_label (&a1
->source_addr
);
1412 = get_label ((struct sockaddr_storage
*) a2
->dest_addr
->ai_addr
);
1413 int a2_src_label
= get_label (&a2
->source_addr
);
1415 if (a1_dst_label
== a1_src_label
&& a2_dst_label
!= a2_src_label
)
1417 if (a1_dst_label
!= a1_src_label
&& a2_dst_label
== a2_src_label
)
1422 /* Rule 6: Prefer higher precedence. */
1424 = get_precedence ((struct sockaddr_storage
*) a1
->dest_addr
->ai_addr
);
1426 = get_precedence ((struct sockaddr_storage
*) a2
->dest_addr
->ai_addr
);
1428 if (a1_prec
> a2_prec
)
1430 if (a1_prec
< a2_prec
)
1434 /* Rule 7: Prefer native transport. */
1435 if (a1
->got_source_addr
)
1437 if (!(a1
->source_addr_flags
& in6ai_temporary
)
1438 && (a1
->source_addr_flags
& in6ai_temporary
))
1440 if ((a1
->source_addr_flags
& in6ai_temporary
)
1441 && !(a1
->source_addr_flags
& in6ai_temporary
))
1444 /* XXX Do we need to check anything beside temporary addresses? */
1448 /* Rule 8: Prefer smaller scope. */
1449 if (a1_dst_scope
< a2_dst_scope
)
1451 if (a1_dst_scope
> a2_dst_scope
)
1455 /* Rule 9: Use longest matching prefix. */
1456 if (a1
->got_source_addr
1457 && a1
->dest_addr
->ai_family
== a2
->dest_addr
->ai_family
)
1462 if (a1
->dest_addr
->ai_family
== PF_INET
)
1464 assert (a1
->source_addr
.ss_family
== PF_INET
);
1465 assert (a2
->source_addr
.ss_family
== PF_INET
);
1467 struct sockaddr_in
*in1_dst
;
1468 struct sockaddr_in
*in1_src
;
1469 struct sockaddr_in
*in2_dst
;
1470 struct sockaddr_in
*in2_src
;
1472 in1_dst
= (struct sockaddr_in
*) a1
->dest_addr
->ai_addr
;
1473 in1_src
= (struct sockaddr_in
*) &a1
->source_addr
;
1474 in2_dst
= (struct sockaddr_in
*) a2
->dest_addr
->ai_addr
;
1475 in2_src
= (struct sockaddr_in
*) &a2
->source_addr
;
1477 bit1
= fls (ntohl (in1_dst
->sin_addr
.s_addr
1478 ^ in1_src
->sin_addr
.s_addr
));
1479 bit2
= fls (ntohl (in2_dst
->sin_addr
.s_addr
1480 ^ in2_src
->sin_addr
.s_addr
));
1482 else if (a1
->dest_addr
->ai_family
== PF_INET6
)
1484 assert (a1
->source_addr
.ss_family
== PF_INET6
);
1485 assert (a2
->source_addr
.ss_family
== PF_INET6
);
1487 struct sockaddr_in6
*in1_dst
;
1488 struct sockaddr_in6
*in1_src
;
1489 struct sockaddr_in6
*in2_dst
;
1490 struct sockaddr_in6
*in2_src
;
1492 in1_dst
= (struct sockaddr_in6
*) a1
->dest_addr
->ai_addr
;
1493 in1_src
= (struct sockaddr_in6
*) &a1
->source_addr
;
1494 in2_dst
= (struct sockaddr_in6
*) a2
->dest_addr
->ai_addr
;
1495 in2_src
= (struct sockaddr_in6
*) &a2
->source_addr
;
1498 for (i
= 0; i
< 4; ++i
)
1499 if (in1_dst
->sin6_addr
.s6_addr32
[i
]
1500 != in1_src
->sin6_addr
.s6_addr32
[i
]
1501 || (in2_dst
->sin6_addr
.s6_addr32
[i
]
1502 != in2_src
->sin6_addr
.s6_addr32
[i
]))
1507 bit1
= fls (ntohl (in1_dst
->sin6_addr
.s6_addr32
[i
]
1508 ^ in1_src
->sin6_addr
.s6_addr32
[i
]));
1509 bit2
= fls (ntohl (in2_dst
->sin6_addr
.s6_addr32
[i
]
1510 ^ in2_src
->sin6_addr
.s6_addr32
[i
]));
1521 /* Rule 10: Otherwise, leave the order unchanged. */
1527 in6aicmp (const void *p1
, const void *p2
)
1529 struct in6addrinfo
*a1
= (struct in6addrinfo
*) p1
;
1530 struct in6addrinfo
*a2
= (struct in6addrinfo
*) p2
;
1532 return memcmp (a1
->addr
, a2
->addr
, sizeof (a1
->addr
));
1536 /* Name of the config file for RFC 3484 sorting (for now). */
1537 #define GAICONF_FNAME "/etc/gai.conf"
1540 /* Nozero if we are supposed to reload the config file automatically
1541 whenever it changed. */
1542 static int gaiconf_reload_flag
;
1544 /* Last modification time. */
1545 static struct timespec gaiconf_mtime
;
1548 libc_freeres_fn(fini
)
1550 if (labels
!= default_labels
)
1552 const struct prefixentry
*old
= labels
;
1553 labels
= default_labels
;
1554 free ((void *) old
);
1557 if (precedence
!= default_precedence
)
1559 const struct prefixentry
*old
= precedence
;
1560 precedence
= default_precedence
;
1561 free ((void *) old
);
1568 struct prefixentry entry
;
1569 struct prefixlist
*next
;
1574 free_prefixlist (struct prefixlist
*list
)
1576 while (list
!= NULL
)
1578 struct prefixlist
*oldp
= list
;
1586 prefixcmp (const void *p1
, const void *p2
)
1588 const struct prefixentry
*e1
= (const struct prefixentry
*) p1
;
1589 const struct prefixentry
*e2
= (const struct prefixentry
*) p2
;
1591 if (e1
->bits
< e2
->bits
)
1593 if (e1
->bits
== e2
->bits
)
1602 struct prefixlist
*labellist
= NULL
;
1603 size_t nlabellist
= 0;
1604 bool labellist_nullbits
= false;
1605 struct prefixlist
*precedencelist
= NULL
;
1606 size_t nprecedencelist
= 0;
1607 bool precedencelist_nullbits
= false;
1609 FILE *fp
= fopen (GAICONF_FNAME
, "rc");
1613 if (__fxstat64 (_STAT_VER
, fileno (fp
), &st
) != 0)
1622 __fsetlocking (fp
, FSETLOCKING_BYCALLER
);
1624 while (!feof_unlocked (fp
))
1626 ssize_t n
= __getline (&line
, &linelen
, fp
);
1630 /* Handle comments. No escaping possible so this is easy. */
1631 char *cp
= strchr (line
, '#');
1636 while (isspace (*cp
))
1640 while (*cp
!= '\0' && !isspace (*cp
))
1642 size_t cmdlen
= cp
- cmd
;
1646 while (isspace (*cp
))
1650 while (*cp
!= '\0' && !isspace (*cp
))
1652 size_t val1len
= cp
- cmd
;
1654 /* We always need at least two values. */
1660 while (isspace (*cp
))
1664 while (*cp
!= '\0' && !isspace (*cp
))
1667 /* Ignore the rest of the line. */
1670 struct prefixlist
**listp
;
1676 if (strcmp (cmd
, "label") == 0)
1678 struct in6_addr prefix
;
1679 unsigned long int bits
;
1680 unsigned long int val
;
1685 nullbitsp
= &labellist_nullbits
;
1690 cp
= strchr (val1
, '/');
1693 if (inet_pton (AF_INET6
, val1
, &prefix
)
1695 || (bits
= strtoul (cp
, &endp
, 10)) != ULONG_MAX
1699 && ((val
= strtoul (val2
, &endp
, 10)) != ULONG_MAX
1704 struct prefixlist
*newp
= malloc (sizeof (*newp
));
1712 memcpy (&newp
->entry
.prefix
, &prefix
, sizeof (prefix
));
1713 newp
->entry
.bits
= bits
;
1714 newp
->entry
.val
= val
;
1715 newp
->next
= *listp
;
1718 *nullbitsp
|= bits
== 0;
1724 if (strcmp (cmd
, "reload") == 0)
1725 gaiconf_reload_flag
= strcmp (val1
, "yes") == 0;
1729 if (strcmp (cmd
, "precedence") == 0)
1731 listp
= &precedencelist
;
1732 lenp
= &nprecedencelist
;
1733 nullbitsp
= &precedencelist_nullbits
;
1744 /* Create the array for the labels. */
1745 struct prefixentry
*new_labels
;
1748 if (!labellist_nullbits
)
1750 new_labels
= malloc (nlabellist
* sizeof (*new_labels
));
1751 if (new_labels
== NULL
)
1755 if (!labellist_nullbits
)
1758 memset (&new_labels
[i
].prefix
, '\0', sizeof (struct in6_addr
));
1759 new_labels
[i
].bits
= 0;
1760 new_labels
[i
].val
= 1;
1763 struct prefixlist
*l
= labellist
;
1766 new_labels
[i
] = l
->entry
;
1769 free_prefixlist (labellist
);
1771 /* Sort the entries so that the most specific ones are at
1773 qsort (new_labels
, nlabellist
, sizeof (*new_labels
), prefixcmp
);
1776 new_labels
= (struct prefixentry
*) default_labels
;
1778 struct prefixentry
*new_precedence
;
1779 if (nprecedencelist
> 0)
1781 if (!precedencelist_nullbits
)
1783 new_precedence
= malloc (nprecedencelist
* sizeof (*new_precedence
));
1784 if (new_precedence
== NULL
)
1786 if (new_labels
!= default_labels
)
1791 int i
= nprecedencelist
;
1792 if (!precedencelist_nullbits
)
1795 memset (&new_precedence
[i
].prefix
, '\0',
1796 sizeof (struct in6_addr
));
1797 new_precedence
[i
].bits
= 0;
1798 new_precedence
[i
].val
= 40;
1801 struct prefixlist
*l
= precedencelist
;
1804 new_precedence
[i
] = l
->entry
;
1807 free_prefixlist (precedencelist
);
1809 /* Sort the entries so that the most specific ones are at
1811 qsort (new_precedence
, nprecedencelist
, sizeof (*new_labels
),
1815 new_precedence
= (struct prefixentry
*) default_precedence
;
1817 /* Now we are ready to replace the values. */
1818 const struct prefixentry
*old
= labels
;
1819 labels
= new_labels
;
1820 if (old
!= default_labels
)
1821 free ((void *) old
);
1824 precedence
= new_precedence
;
1825 if (old
!= default_precedence
)
1826 free ((void *) old
);
1828 gaiconf_mtime
= st
.st_mtim
;
1833 free_prefixlist (labellist
);
1834 free_prefixlist (precedencelist
);
1836 /* If we previously read the file but it is gone now, free the
1837 old data and use the builtin one. Leave the reload flag
1845 gaiconf_reload (void)
1848 if (__xstat64 (_STAT_VER
, GAICONF_FNAME
, &st
) != 0
1849 || memcmp (&st
.st_mtim
, &gaiconf_mtime
, sizeof (gaiconf_mtime
)) != 0)
1855 getaddrinfo (const char *name
, const char *service
,
1856 const struct addrinfo
*hints
, struct addrinfo
**pai
)
1858 int i
= 0, last_i
= 0;
1860 struct addrinfo
*p
= NULL
;
1861 struct gaih_service gaih_service
, *pservice
;
1862 struct addrinfo local_hints
;
1864 if (name
!= NULL
&& name
[0] == '*' && name
[1] == 0)
1867 if (service
!= NULL
&& service
[0] == '*' && service
[1] == 0)
1870 if (name
== NULL
&& service
== NULL
)
1874 hints
= &default_hints
;
1877 & ~(AI_PASSIVE
|AI_CANONNAME
|AI_NUMERICHOST
|AI_ADDRCONFIG
|AI_V4MAPPED
1879 |AI_IDN
|AI_CANONIDN
|AI_IDN_ALLOW_UNASSIGNED
1880 |AI_IDN_USE_STD3_ASCII_RULES
1882 |AI_NUMERICSERV
|AI_ALL
))
1883 return EAI_BADFLAGS
;
1885 if ((hints
->ai_flags
& AI_CANONNAME
) && name
== NULL
)
1886 return EAI_BADFLAGS
;
1888 struct in6addrinfo
*in6ai
= NULL
;
1890 bool seen_ipv4
= false;
1891 bool seen_ipv6
= false;
1892 /* We might need information about what kind of interfaces are available.
1893 But even if AI_ADDRCONFIG is not used, if the user requested IPv6
1894 addresses we have to know whether an address is deprecated or
1896 if ((hints
->ai_flags
& AI_ADDRCONFIG
) || hints
->ai_family
== PF_UNSPEC
1897 || hints
->ai_family
== PF_INET6
)
1898 /* Determine whether we have IPv4 or IPv6 interfaces or both. We
1899 cannot cache the results since new interfaces could be added at
1901 __check_pf (&seen_ipv4
, &seen_ipv6
, &in6ai
, &in6ailen
);
1903 if (hints
->ai_flags
& AI_ADDRCONFIG
)
1905 /* Now make a decision on what we return, if anything. */
1906 if (hints
->ai_family
== PF_UNSPEC
&& (seen_ipv4
|| seen_ipv6
))
1908 /* If we haven't seen both IPv4 and IPv6 interfaces we can
1909 narrow down the search. */
1910 if (! seen_ipv4
|| ! seen_ipv6
)
1912 local_hints
= *hints
;
1913 local_hints
.ai_family
= seen_ipv4
? PF_INET
: PF_INET6
;
1914 hints
= &local_hints
;
1917 else if ((hints
->ai_family
== PF_INET
&& ! seen_ipv4
)
1918 || (hints
->ai_family
== PF_INET6
&& ! seen_ipv6
))
1920 /* We cannot possibly return a valid answer. */
1926 if (service
&& service
[0])
1929 gaih_service
.name
= service
;
1930 gaih_service
.num
= strtoul (gaih_service
.name
, &c
, 10);
1933 if (hints
->ai_flags
& AI_NUMERICSERV
)
1939 gaih_service
.num
= -1;
1942 pservice
= &gaih_service
;
1947 struct addrinfo
**end
;
1953 unsigned int naddrs
= 0;
1955 /* If we would support more protocols than just IPv4 and IPv6 we
1956 would iterate over a table with appropriate callback functions.
1957 Since we currently only handle IPv4 and IPv6 this is not
1959 const struct gaih
*g
= gaih
;
1960 const struct gaih
*pg
= NULL
;
1964 if (hints
->ai_family
== g
->family
|| hints
->ai_family
== AF_UNSPEC
)
1967 if (pg
== NULL
|| pg
->gaih
!= g
->gaih
)
1970 i
= g
->gaih (name
, pservice
, hints
, end
, &naddrs
);
1973 /* EAI_NODATA is a more specific result as it says that
1974 we found a result but it is not usable. */
1975 if (last_i
!= (GAIH_OKIFUNSPEC
| -EAI_NODATA
))
1978 if (hints
->ai_family
== AF_UNSPEC
&& (i
& GAIH_OKIFUNSPEC
))
1987 return -(i
& GAIH_EAI
);
1992 end
= &((*end
)->ai_next
);
2006 if (hints
->ai_family
== AF_UNSPEC
|| hints
->ai_family
== AF_INET
2007 || hints
->ai_family
== AF_INET6
)
2009 last_i
= gaih_inet (name
, pservice
, hints
, end
, &naddrs
);
2015 return -(last_i
& GAIH_EAI
);
2020 end
= &((*end
)->ai_next
);
2033 /* Read the config file. */
2034 __libc_once_define (static, once
);
2035 __typeof (once
) old_once
= once
;
2036 __libc_once (once
, gaiconf_init
);
2037 if (old_once
&& gaiconf_reload_flag
)
2040 /* Sort results according to RFC 3484. */
2041 struct sort_result results
[nresults
];
2043 struct addrinfo
*last
= NULL
;
2044 char *canonname
= NULL
;
2046 /* If we have information about deprecated and temporary address
2047 sort the array now. */
2049 qsort (in6ai
, in6ailen
, sizeof (*in6ai
), in6aicmp
);
2051 for (i
= 0, q
= p
; q
!= NULL
; ++i
, last
= q
, q
= q
->ai_next
)
2053 results
[i
].dest_addr
= q
;
2054 results
[i
].got_source_addr
= false;
2056 /* If we just looked up the address for a different
2057 protocol, reuse the result. */
2058 if (last
!= NULL
&& last
->ai_addrlen
== q
->ai_addrlen
2059 && memcmp (last
->ai_addr
, q
->ai_addr
, q
->ai_addrlen
) == 0)
2061 memcpy (&results
[i
].source_addr
, &results
[i
- 1].source_addr
,
2062 results
[i
- 1].source_addr_len
);
2063 results
[i
].source_addr_len
= results
[i
- 1].source_addr_len
;
2064 results
[i
].got_source_addr
= results
[i
- 1].got_source_addr
;
2065 results
[i
].source_addr_flags
= results
[i
- 1].source_addr_flags
;
2069 results
[i
].source_addr_flags
= 0;
2071 /* We overwrite the type with SOCK_DGRAM since we do not
2072 want connect() to connect to the other side. If we
2073 cannot determine the source address remember this
2075 int fd
= __socket (q
->ai_family
, SOCK_DGRAM
, IPPROTO_IP
);
2076 socklen_t sl
= sizeof (results
[i
].source_addr
);
2078 && __connect (fd
, q
->ai_addr
, q
->ai_addrlen
) == 0
2079 && __getsockname (fd
,
2080 (struct sockaddr
*) &results
[i
].source_addr
,
2083 results
[i
].source_addr_len
= sl
;
2084 results
[i
].got_source_addr
= true;
2086 if (q
->ai_family
== PF_INET6
&& in6ai
!= NULL
)
2088 /* See whether the address is the list of deprecated
2089 or temporary addresses. */
2090 struct in6addrinfo tmp
;
2091 memcpy (tmp
.addr
, q
->ai_addr
, IN6ADDRSZ
);
2093 struct in6addrinfo
*found
2094 = bsearch (&tmp
, in6ai
, in6ailen
, sizeof (*in6ai
),
2097 results
[i
].source_addr_flags
= found
->flags
;
2101 /* Just make sure that if we have to process the same
2102 address again we do not copy any memory. */
2103 results
[i
].source_addr_len
= 0;
2106 close_not_cancel_no_status (fd
);
2109 /* Remember the canonical name. */
2110 if (q
->ai_canonname
!= NULL
)
2112 assert (canonname
== NULL
);
2113 canonname
= q
->ai_canonname
;
2114 q
->ai_canonname
= NULL
;
2118 /* We got all the source addresses we can get, now sort using
2120 qsort (results
, nresults
, sizeof (results
[0]), rfc3484_sort
);
2122 /* Queue the results up as they come out of sorting. */
2123 q
= p
= results
[0].dest_addr
;
2124 for (i
= 1; i
< nresults
; ++i
)
2125 q
= q
->ai_next
= results
[i
].dest_addr
;
2128 /* Fill in the canonical name into the new first entry. */
2129 p
->ai_canonname
= canonname
;
2140 if (pai
== NULL
&& last_i
== 0)
2143 return last_i
? -(last_i
& GAIH_EAI
) : EAI_NONAME
;
2145 libc_hidden_def (getaddrinfo
)
2147 static_link_warning (getaddrinfo
)
2150 freeaddrinfo (struct addrinfo
*ai
)
2158 free (p
->ai_canonname
);
2162 libc_hidden_def (freeaddrinfo
)