]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/posix/getaddrinfo.c
.
[thirdparty/glibc.git] / sysdeps / posix / getaddrinfo.c
CommitLineData
46ec036d
UD
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.
aeb25823 184. [The copyright holder has authorized the removal of this clause.]
46ec036d
UD
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
c0bc5f7b 38#include <assert.h>
77dd4c3b 39#include <ctype.h>
c0bc5f7b 40#include <errno.h>
925c3c5c 41#include <ifaddrs.h>
c0bc5f7b 42#include <netdb.h>
9c42c64d 43#include <resolv.h>
f24dca48 44#include <stdbool.h>
c0bc5f7b 45#include <stdio.h>
77dd4c3b 46#include <stdio_ext.h>
46ec036d 47#include <stdlib.h>
c0bc5f7b 48#include <string.h>
c0bc5f7b 49#include <arpa/inet.h>
77dd4c3b 50#include <net/if.h>
a334319f 51#include <netinet/in.h>
77dd4c3b
UD
52#include <sys/socket.h>
53#include <sys/stat.h>
c0bc5f7b
UD
54#include <sys/types.h>
55#include <sys/un.h>
56#include <sys/utsname.h>
77dd4c3b 57#include <unistd.h>
218d76e0 58#include <nsswitch.h>
77dd4c3b 59#include <bits/libc-lock.h>
5ddb5bf5 60#include <not-cancel.h>
d19687d6 61#include <nscd/nscd-client.h>
62417d7e 62#include <nscd/nscd_proto.h>
1fb05e3d 63
de079fee 64#ifdef HAVE_LIBIDN
e2fd3cbe 65extern int __idna_to_ascii_lz (const char *input, char **output, int flags);
de079fee
UD
66extern int __idna_to_unicode_lzlz (const char *input, char **output,
67 int flags);
68# include <libidn/idna.h>
69#endif
e2fd3cbe 70
46ec036d
UD
71#define GAIH_OKIFUNSPEC 0x0100
72#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
73
40a55d20 74#ifndef UNIX_PATH_MAX
3af48b5b 75# define UNIX_PATH_MAX 108
40a55d20 76#endif
46ec036d 77
40a55d20
UD
78struct gaih_service
79 {
80 const char *name;
81 int num;
82 };
46ec036d 83
40a55d20
UD
84struct gaih_servtuple
85 {
86 struct gaih_servtuple *next;
87 int socktype;
88 int protocol;
89 int port;
90 };
46ec036d 91
3e2d61a3 92static const struct gaih_servtuple nullserv;
46ec036d 93
40a55d20
UD
94struct gaih_addrtuple
95 {
96 struct gaih_addrtuple *next;
b0d8b23d 97 char *name;
40a55d20 98 int family;
28977c2c 99 uint32_t addr[4];
c0bc5f7b 100 uint32_t scopeid;
40a55d20 101 };
46ec036d 102
40a55d20
UD
103struct gaih_typeproto
104 {
105 int socktype;
106 int protocol;
3e2d61a3 107 char name[4];
f3ac48d0 108 int protoflag;
40a55d20 109 };
46ec036d 110
f3ac48d0
UD
111/* Values for `protoflag'. */
112#define GAI_PROTO_NOSERVICE 1
85599e53 113#define GAI_PROTO_PROTOANY 2
f3ac48d0 114
3e2d61a3 115static const struct gaih_typeproto gaih_inet_typeproto[] =
40a55d20 116{
3e2d61a3
UD
117 { 0, 0, "", 0 },
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 },
121 { 0, 0, "", 0 }
46ec036d
UD
122};
123
40a55d20
UD
124struct gaih
125 {
126 int family;
127 int (*gaih)(const char *name, const struct gaih_service *service,
01abbc0f
UD
128 const struct addrinfo *req, struct addrinfo **pai,
129 unsigned int *naddrs);
40a55d20
UD
130 };
131
3e2d61a3 132static const struct addrinfo default_hints =
925c3c5c
UD
133 {
134 .ai_flags = AI_DEFAULT,
135 .ai_family = PF_UNSPEC,
136 .ai_socktype = 0,
137 .ai_protocol = 0,
138 .ai_addrlen = 0,
139 .ai_addr = NULL,
140 .ai_canonname = NULL,
141 .ai_next = NULL
142 };
40a55d20
UD
143
144
64b7897d
UD
145#if 0
146/* Using Unix sockets this way is a security risk. */
40a55d20
UD
147static int
148gaih_local (const char *name, const struct gaih_service *service,
149 const struct addrinfo *req, struct addrinfo **pai)
1fb05e3d
UD
150{
151 struct utsname utsname;
152
f1a785ac
UD
153 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
154 return GAIH_OKIFUNSPEC | -EAI_NONAME;
155
40a55d20 156 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
db7dc811 157 if (uname (&utsname) < 0)
1fb05e3d 158 return -EAI_SYSTEM;
1fb05e3d 159
40a55d20
UD
160 if (name != NULL)
161 {
162 if (strcmp(name, "localhost") &&
163 strcmp(name, "local") &&
164 strcmp(name, "unix") &&
165 strcmp(name, utsname.nodename))
166 return GAIH_OKIFUNSPEC | -EAI_NONAME;
167 }
168
a0bf6ac7
UD
169 if (req->ai_protocol || req->ai_socktype)
170 {
3e2d61a3 171 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
f3ac48d0 172
4b1fef84 173 while (tp->name[0]
f3ac48d0 174 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
3a47453d
UD
175 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
176 || (req->ai_protocol != 0
85599e53 177 && !(tp->protoflag & GAI_PROTO_PROTOANY)
3a47453d 178 && req->ai_protocol != tp->protocol)))
f3ac48d0 179 ++tp;
a0bf6ac7 180
4b1fef84 181 if (! tp->name[0])
a0bf6ac7
UD
182 {
183 if (req->ai_socktype)
3af48b5b 184 return GAIH_OKIFUNSPEC | -EAI_SOCKTYPE;
a0bf6ac7 185 else
3af48b5b 186 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
a0bf6ac7
UD
187 }
188 }
189
190 *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
40a55d20
UD
191 + ((req->ai_flags & AI_CANONNAME)
192 ? (strlen(utsname.nodename) + 1): 0));
193 if (*pai == NULL)
1fb05e3d
UD
194 return -EAI_MEMORY;
195
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;
a0bf6ac7
UD
201 (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
202 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
40a55d20 203
beb32642 204#ifdef _HAVE_SA_LEN
40a55d20
UD
205 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
206 sizeof (struct sockaddr_un);
beb32642 207#endif /* _HAVE_SA_LEN */
40a55d20 208
1fb05e3d
UD
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);
40a55d20
UD
211
212 if (service)
213 {
214 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
215
216 if (strchr (service->name, '/') != NULL)
217 {
218 if (strlen (service->name) >= sizeof (sunp->sun_path))
219 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
220
221 strcpy (sunp->sun_path, service->name);
222 }
223 else
224 {
225 if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
226 sizeof (sunp->sun_path))
227 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
228
229 __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
230 }
231 }
232 else
233 {
e658b54e
UD
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
237 be created. */
238 char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
239
240 if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
241 0) != 0
242 || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
40a55d20
UD
243 return -EAI_SYSTEM;
244 }
245
1fb05e3d 246 if (req->ai_flags & AI_CANONNAME)
a0bf6ac7
UD
247 (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
248 + sizeof (struct sockaddr_un),
249 utsname.nodename);
1fb05e3d
UD
250 else
251 (*pai)->ai_canonname = NULL;
252 return 0;
40a55d20 253}
64b7897d 254#endif /* 0 */
46ec036d 255
3af48b5b 256
40a55d20 257static int
3e2d61a3 258gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
3af48b5b 259 const struct addrinfo *req, struct gaih_servtuple *st)
46ec036d
UD
260{
261 struct servent *s;
40a55d20 262 size_t tmpbuflen = 1024;
993b3242 263 struct servent ts;
40a55d20
UD
264 char *tmpbuf;
265 int r;
266
267 do
993b3242 268 {
40a55d20 269 tmpbuf = __alloca (tmpbuflen);
40a55d20
UD
270
271 r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
272 &s);
a0bf6ac7 273 if (r != 0 || s == NULL)
993b3242 274 {
a0bf6ac7 275 if (r == ERANGE)
40a55d20
UD
276 tmpbuflen *= 2;
277 else
278 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
993b3242
UD
279 }
280 }
40a55d20 281 while (r);
993b3242 282
238ae1eb
UD
283 st->next = NULL;
284 st->socktype = tp->socktype;
85599e53
UD
285 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
286 ? req->ai_protocol : tp->protocol);
238ae1eb 287 st->port = s->s_port;
46ec036d
UD
288
289 return 0;
290}
291
925c3c5c 292#define gethosts(_family, _type) \
925c3c5c 293 { \
2d26a717
UD
294 int i; \
295 int herrno; \
925c3c5c 296 struct hostent th; \
a4fdd4b8 297 struct hostent *h; \
f04b1e1f 298 char *localcanon = NULL; \
925c3c5c 299 no_data = 0; \
2d26a717 300 while (1) { \
925c3c5c 301 rc = 0; \
7a11603d
UD
302 status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf, tmpbuflen, \
303 &rc, &herrno, NULL, &localcanon)); \
2d26a717
UD
304 if (rc != ERANGE || herrno != NETDB_INTERNAL) \
305 break; \
306 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \
307 } \
925c3c5c
UD
308 if (status == NSS_STATUS_SUCCESS && rc == 0) \
309 h = &th; \
310 else \
311 h = NULL; \
312 if (rc != 0) \
313 { \
314 if (herrno == NETDB_INTERNAL) \
315 { \
316 __set_h_errno (herrno); \
317 return -EAI_SYSTEM; \
318 } \
319 if (herrno == TRY_AGAIN) \
320 no_data = EAI_AGAIN; \
321 else \
322 no_data = herrno == NO_DATA; \
323 } \
324 else if (h != NULL) \
325 { \
326 for (i = 0; h->h_addr_list[i]; i++) \
327 { \
28977c2c
UD
328 if (*pat == NULL) \
329 { \
330 *pat = __alloca (sizeof (struct gaih_addrtuple)); \
331 (*pat)->scopeid = 0; \
332 } \
333 uint32_t *addr = (*pat)->addr; \
925c3c5c 334 (*pat)->next = NULL; \
b0d8b23d 335 (*pat)->name = i == 0 ? strdupa (h->h_name) : NULL; \
28977c2c
UD
336 if (_family == AF_INET && req->ai_family == AF_INET6) \
337 { \
338 (*pat)->family = AF_INET6; \
339 addr[3] = *(uint32_t *) h->h_addr_list[i]; \
340 addr[2] = htonl (0xffff); \
341 addr[1] = 0; \
342 addr[0] = 0; \
343 } \
344 else \
345 { \
346 (*pat)->family = _family; \
347 memcpy (addr, h->h_addr_list[i], sizeof(_type)); \
348 } \
925c3c5c
UD
349 pat = &((*pat)->next); \
350 } \
28977c2c 351 \
7a11603d 352 if (localcanon != NULL && canon == NULL) \
f04b1e1f
UD
353 canon = strdupa (localcanon); \
354 \
28977c2c
UD
355 if (_family == AF_INET6 && i > 0) \
356 got_ipv6 = true; \
925c3c5c 357 } \
218d76e0
UD
358 }
359
28977c2c 360
f04b1e1f 361typedef enum nss_status (*nss_gethostbyname3_r)
218d76e0
UD
362 (const char *name, int af, struct hostent *host,
363 char *buffer, size_t buflen, int *errnop,
f04b1e1f 364 int *h_errnop, int32_t *ttlp, char **canonp);
28977c2c
UD
365typedef enum nss_status (*nss_getcanonname_r)
366 (const char *name, char *buffer, size_t buflen, char **result,
367 int *errnop, int *h_errnop);
218d76e0
UD
368extern service_user *__nss_hosts_database attribute_hidden;
369
3af48b5b 370
40a55d20
UD
371static int
372gaih_inet (const char *name, const struct gaih_service *service,
01abbc0f
UD
373 const struct addrinfo *req, struct addrinfo **pai,
374 unsigned int *naddrs)
46ec036d 375{
3e2d61a3
UD
376 const struct gaih_typeproto *tp = gaih_inet_typeproto;
377 struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
1fb05e3d 378 struct gaih_addrtuple *at = NULL;
40a55d20 379 int rc;
925c3c5c 380 bool got_ipv6 = false;
28977c2c 381 const char *canon = NULL;
b6c0f679 382 const char *orig_name = name;
46ec036d 383
40a55d20
UD
384 if (req->ai_protocol || req->ai_socktype)
385 {
f3ac48d0
UD
386 ++tp;
387
4b1fef84 388 while (tp->name[0]
3a47453d
UD
389 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
390 || (req->ai_protocol != 0
85599e53 391 && !(tp->protoflag & GAI_PROTO_PROTOANY)
3a47453d 392 && req->ai_protocol != tp->protocol)))
f3ac48d0
UD
393 ++tp;
394
4b1fef84 395 if (! tp->name[0])
6e4c40ba
UD
396 {
397 if (req->ai_socktype)
3af48b5b 398 return GAIH_OKIFUNSPEC | -EAI_SOCKTYPE;
6e4c40ba 399 else
3af48b5b 400 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
6e4c40ba 401 }
40a55d20
UD
402 }
403
29546dd9 404 int port = 0;
40a55d20
UD
405 if (service != NULL)
406 {
f3ac48d0 407 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
3af48b5b 408 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
f3ac48d0 409
40a55d20
UD
410 if (service->num < 0)
411 {
4b1fef84 412 if (tp->name[0])
40a55d20 413 {
238ae1eb
UD
414 st = (struct gaih_servtuple *)
415 __alloca (sizeof (struct gaih_servtuple));
416
85599e53 417 if ((rc = gaih_inet_serv (service->name, tp, req, st)))
40a55d20
UD
418 return rc;
419 }
420 else
421 {
422 struct gaih_servtuple **pst = &st;
4b1fef84 423 for (tp++; tp->name[0]; tp++)
40a55d20 424 {
3a47453d
UD
425 struct gaih_servtuple *newp;
426
427 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
428 continue;
429
84a4fd33
UD
430 if (req->ai_socktype != 0
431 && req->ai_socktype != tp->socktype)
432 continue;
85599e53
UD
433 if (req->ai_protocol != 0
434 && !(tp->protoflag & GAI_PROTO_PROTOANY)
435 && req->ai_protocol != tp->protocol)
436 continue;
84a4fd33 437
3a47453d 438 newp = (struct gaih_servtuple *)
238ae1eb
UD
439 __alloca (sizeof (struct gaih_servtuple));
440
85599e53 441 if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
40a55d20
UD
442 {
443 if (rc & GAIH_OKIFUNSPEC)
444 continue;
445 return rc;
446 }
238ae1eb
UD
447
448 *pst = newp;
449 pst = &(newp->next);
40a55d20 450 }
3e2d61a3 451 if (st == (struct gaih_servtuple *) &nullserv)
3af48b5b 452 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
40a55d20 453 }
46ec036d 454 }
40a55d20
UD
455 else
456 {
29546dd9
UD
457 port = htons (service->num);
458 goto got_port;
46ec036d 459 }
40a55d20 460 }
84a4fd33
UD
461 else
462 {
29546dd9
UD
463 got_port:
464
465 if (req->ai_socktype || req->ai_protocol)
466 {
467 st = __alloca (sizeof (struct gaih_servtuple));
468 st->next = NULL;
469 st->socktype = tp->socktype;
470 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
471 ? req->ai_protocol : tp->protocol);
472 st->port = port;
473 }
474 else
84a4fd33 475 {
29546dd9
UD
476 /* Neither socket type nor protocol is set. Return all socket types
477 we know about. */
478 struct gaih_servtuple **lastp = &st;
479 for (++tp; tp->name[0]; ++tp)
480 {
481 struct gaih_servtuple *newp;
84a4fd33 482
29546dd9
UD
483 newp = __alloca (sizeof (struct gaih_servtuple));
484 newp->next = NULL;
485 newp->socktype = tp->socktype;
486 newp->protocol = tp->protocol;
487 newp->port = port;
84a4fd33 488
29546dd9
UD
489 *lastp = newp;
490 lastp = &newp->next;
491 }
84a4fd33
UD
492 }
493 }
40a55d20
UD
494
495 if (name != NULL)
496 {
a0bf6ac7 497 at = __alloca (sizeof (struct gaih_addrtuple));
46ec036d 498
a0bf6ac7 499 at->family = AF_UNSPEC;
c0bc5f7b 500 at->scopeid = 0;
40a55d20 501 at->next = NULL;
46ec036d 502
e2fd3cbe
UD
503#ifdef HAVE_LIBIDN
504 if (req->ai_flags & AI_IDN)
505 {
3a0e90bd
UD
506 int idn_flags = 0;
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;
511
e2fd3cbe 512 char *p = NULL;
3a0e90bd 513 rc = __idna_to_ascii_lz (name, &p, idn_flags);
e2fd3cbe 514 if (rc != IDNA_SUCCESS)
de079fee
UD
515 {
516 if (rc == IDNA_MALLOC_ERROR)
517 return -EAI_MEMORY;
518 if (rc == IDNA_DLOPEN_ERROR)
519 return -EAI_SYSTEM;
520 return -EAI_IDN_ENCODE;
521 }
522 /* In case the output string is the same as the input string
523 no new string has been allocated. */
524 if (p != name)
525 {
526 name = strdupa (p);
527 free (p);
528 }
e2fd3cbe
UD
529 }
530#endif
531
c1d98085 532 if (__inet_aton (name, (struct in_addr *) at->addr) != 0)
a0bf6ac7
UD
533 {
534 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
535 at->family = AF_INET;
846d1362 536 else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
925c3c5c 537 {
28977c2c
UD
538 at->addr[3] = at->addr[0];
539 at->addr[2] = htonl (0xffff);
540 at->addr[1] = 0;
541 at->addr[0] = 0;
c1d98085 542 at->family = AF_INET6;
925c3c5c 543 }
a0bf6ac7
UD
544 else
545 return -EAI_ADDRFAMILY;
4376935c 546
4376935c 547 if (req->ai_flags & AI_CANONNAME)
5b353be3 548 canon = name;
a0bf6ac7 549 }
5b353be3 550 else if (at->family == AF_UNSPEC)
a0bf6ac7 551 {
abab6859
UD
552 char *namebuf = (char *) name;
553 char *scope_delim = strchr (name, SCOPE_DELIMITER);
c0bc5f7b 554
abab6859
UD
555 if (__builtin_expect (scope_delim != NULL, 0))
556 {
557 namebuf = alloca (scope_delim - name + 1);
558 *((char *) __mempcpy (namebuf, name, scope_delim - name)) = '\0';
559 }
c0bc5f7b
UD
560
561 if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
562 {
c0bc5f7b
UD
563 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
564 at->family = AF_INET6;
87bb6b6c
UD
565 else if (req->ai_family == AF_INET
566 && IN6_IS_ADDR_V4MAPPED (at->addr))
567 {
28977c2c 568 at->addr[0] = at->addr[3];
87bb6b6c
UD
569 at->family = AF_INET;
570 }
c0bc5f7b
UD
571 else
572 return -EAI_ADDRFAMILY;
573
574 if (scope_delim != NULL)
575 {
576 int try_numericscope = 0;
577 if (IN6_IS_ADDR_LINKLOCAL (at->addr)
578 || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
579 {
580 at->scopeid = if_nametoindex (scope_delim + 1);
581 if (at->scopeid == 0)
582 try_numericscope = 1;
583 }
584 else
585 try_numericscope = 1;
586
587 if (try_numericscope != 0)
588 {
589 char *end;
590 assert (sizeof (uint32_t) <= sizeof (unsigned long));
591 at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
592 10);
593 if (*end != '\0')
594 return GAIH_OKIFUNSPEC | -EAI_NONAME;
595 }
596 }
4376935c 597
5b353be3
UD
598 if (req->ai_flags & AI_CANONNAME)
599 canon = name;
c0bc5f7b 600 }
a0bf6ac7 601 }
40a55d20 602
ce75c139 603 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
40a55d20 604 {
40a55d20 605 struct gaih_addrtuple **pat = &at;
a0bf6ac7 606 int no_data = 0;
218d76e0 607 int no_inet6_data = 0;
28977c2c
UD
608 service_user *nip = NULL;
609 enum nss_status inet6_status = NSS_STATUS_UNAVAIL;
610 enum nss_status status = NSS_STATUS_UNAVAIL;
611 int no_more;
28977c2c 612 int old_res_options;
d19687d6
UD
613
614 /* If we do not have to look for IPv4 and IPv6 together, use
615 the simple, old functions. */
abab6859
UD
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)))
d19687d6
UD
620 {
621 int family = req->ai_family;
622 size_t tmpbuflen = 512;
623 char *tmpbuf = alloca (tmpbuflen);
624 int rc;
625 struct hostent th;
626 struct hostent *h;
627 int herrno;
628
629 simple_again:
630 while (1)
631 {
632 rc = __gethostbyname2_r (name, family, &th, tmpbuf,
633 tmpbuflen, &h, &herrno);
634 if (rc != ERANGE || herrno != NETDB_INTERNAL)
635 break;
636 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
637 }
638
639 if (rc == 0)
640 {
641 if (h == NULL)
642 {
643 if (req->ai_family == AF_INET6
644 && (req->ai_flags & AI_V4MAPPED)
645 && family == AF_INET6)
646 {
647 /* Try again, this time looking for IPv4
648 addresses. */
649 family = AF_INET;
650 goto simple_again;
651 }
652 }
653 else
654 {
655 /* We found data, now convert it into the list. */
656 for (int i = 0; h->h_addr_list[i]; ++i)
657 {
658 if (*pat == NULL)
659 {
660 *pat = __alloca (sizeof (struct gaih_addrtuple));
661 (*pat)->scopeid = 0;
662 }
663 (*pat)->next = NULL;
664 (*pat)->family = req->ai_family;
665 if (family == req->ai_family)
666 memcpy ((*pat)->addr, h->h_addr_list[i],
667 h->h_length);
668 else
669 {
9cfe5381 670 uint32_t *addr = (uint32_t *) (*pat)->addr;
d19687d6
UD
671 addr[3] = *(uint32_t *) h->h_addr_list[i];
672 addr[2] = htonl (0xffff);
673 addr[1] = 0;
674 addr[0] = 0;
675 }
676 pat = &((*pat)->next);
677 }
678 }
679 }
680 else
681 {
682 if (herrno == NETDB_INTERNAL)
683 {
684 __set_h_errno (herrno);
685 return -EAI_SYSTEM;
686 }
687 if (herrno == TRY_AGAIN)
688 {
689 return -EAI_AGAIN;
690 }
691 /* We made requests but they turned out no data.
692 The name is known, though. */
3af48b5b 693 return GAIH_OKIFUNSPEC | -EAI_NODATA;
d19687d6
UD
694 }
695
696 goto process_list;
697 }
698
699#ifdef USE_NSCD
62417d7e
UD
700 if (__nss_not_use_nscd_hosts > 0
701 && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
702 __nss_not_use_nscd_hosts = 0;
d19687d6 703
62417d7e
UD
704 if (!__nss_not_use_nscd_hosts)
705 {
706 /* Try to use nscd. */
707 struct nscd_ai_result *air = NULL;
708 int herrno;
709 int err = __nscd_getai (name, &air, &herrno);
710 if (air != NULL)
d19687d6 711 {
62417d7e
UD
712 /* Transform into gaih_addrtuple list. */
713 bool added_canon = (req->ai_flags & AI_CANONNAME) == 0;
714 char *addrs = air->addrs;
d19687d6 715
62417d7e 716 for (int i = 0; i < air->naddrs; ++i)
d19687d6 717 {
62417d7e
UD
718 socklen_t size = (air->family[i] == AF_INET
719 ? INADDRSZ : IN6ADDRSZ);
720 if (*pat == NULL)
721 {
722 *pat = __alloca (sizeof (struct gaih_addrtuple));
723 (*pat)->scopeid = 0;
724 }
725 uint32_t *pataddr = (*pat)->addr;
726 (*pat)->next = NULL;
727 if (added_canon || air->canon == NULL)
728 (*pat)->name = NULL;
729 else
730 canon = (*pat)->name = strdupa (air->canon);
731
732 if (air->family[i] == AF_INET
733 && req->ai_family == AF_INET6
734 && (req->ai_flags & AI_V4MAPPED))
735 {
736 (*pat)->family = AF_INET6;
737 pataddr[3] = *(uint32_t *) addrs;
738 pataddr[2] = htonl (0xffff);
739 pataddr[1] = 0;
740 pataddr[0] = 0;
741 pat = &((*pat)->next);
742 added_canon = true;
743 }
744 else if (req->ai_family == AF_UNSPEC
745 || air->family[i] == req->ai_family)
746 {
747 (*pat)->family = air->family[i];
748 memcpy (pataddr, addrs, size);
749 pat = &((*pat)->next);
750 added_canon = true;
751 if (air->family[i] == AF_INET6)
752 got_ipv6 = true;
753 }
754 addrs += size;
d19687d6 755 }
d19687d6 756
6535f55f
UD
757 free (air);
758
62417d7e 759 if (at->family == AF_UNSPEC)
3af48b5b 760 return GAIH_OKIFUNSPEC | -EAI_NONAME;
d19687d6 761
62417d7e
UD
762 goto process_list;
763 }
764 else if (err != 0 && __nss_not_use_nscd_hosts == 0)
765 {
766 if (herrno == NETDB_INTERNAL && errno == ENOMEM)
767 return -EAI_MEMORY;
768 if (herrno == TRY_AGAIN)
769 return -EAI_AGAIN;
770 return -EAI_SYSTEM;
771 }
d19687d6
UD
772 }
773#endif
28977c2c
UD
774
775 if (__nss_hosts_database != NULL)
776 {
777 no_more = 0;
778 nip = __nss_hosts_database;
779 }
780 else
781 no_more = __nss_database_lookup ("hosts", NULL,
782 "dns [!UNAVAIL=return] files",
783 &nip);
784
785 if (__res_maybe_init (&_res, 0) == -1)
786 no_more = 1;
787
9c42c64d
UD
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. */
28977c2c
UD
792 old_res_options = _res.options;
793 _res.options &= ~RES_USE_INET6;
40a55d20 794
d19687d6
UD
795 size_t tmpbuflen = 512;
796 char *tmpbuf = alloca (tmpbuflen);
797
28977c2c
UD
798 while (!no_more)
799 {
d7243362
UD
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
805 often fail. */
806 fct = __nss_lookup_function (nip, "gethostbyname3_r");
f04b1e1f
UD
807 if (fct == NULL)
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");
9c42c64d 813
28977c2c 814 if (fct != NULL)
218d76e0 815 {
28977c2c
UD
816 if (req->ai_family == AF_INET6
817 || req->ai_family == AF_UNSPEC)
64ab2317 818 {
28977c2c 819 gethosts (AF_INET6, struct in6_addr);
64ab2317
UD
820 no_inet6_data = no_data;
821 inet6_status = status;
64ab2317 822 }
28977c2c
UD
823 if (req->ai_family == AF_INET
824 || req->ai_family == AF_UNSPEC
825 || (req->ai_family == AF_INET6
2d26a717
UD
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)))
28977c2c
UD
830 {
831 gethosts (AF_INET, struct in_addr);
218d76e0 832
28977c2c
UD
833 if (req->ai_family == AF_INET)
834 {
835 no_inet6_data = no_data;
836 inet6_status = status;
837 }
838 }
218d76e0 839
28977c2c
UD
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)
844 {
f04b1e1f 845 if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
28977c2c 846 {
afd7b703
UD
847 /* If we need the canonical name, get it
848 from the same service as the result. */
849 nss_getcanonname_r cfct;
850 int herrno;
851
852 cfct = __nss_lookup_function (nip, "getcanonname_r");
853 if (cfct != NULL)
854 {
855 const size_t max_fqdn_len = 256;
856 char *buf = alloca (max_fqdn_len);
857 char *s;
858
b0d8b23d 859 if (DL_CALL_FCT (cfct, (at->name ?: name, buf,
afd7b703
UD
860 max_fqdn_len, &s, &rc,
861 &herrno))
862 == NSS_STATUS_SUCCESS)
863 canon = s;
864 else
865 /* Set to name now to avoid using
866 gethostbyaddr. */
867 canon = name;
868 }
28977c2c
UD
869 }
870
871 break;
872 }
873
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;
abab6859
UD
878 else if (status == NSS_STATUS_UNAVAIL
879 && inet6_status != NSS_STATUS_UNAVAIL)
28977c2c 880 status = inet6_status;
218d76e0
UD
881 }
882
28977c2c
UD
883 if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
884 break;
885
886 if (nip->next == NULL)
887 no_more = -1;
888 else
889 nip = nip->next;
2ce1a10f 890 }
a0bf6ac7 891
28977c2c
UD
892 _res.options = old_res_options;
893
5ad81f40 894 if (no_data != 0 && no_inet6_data != 0)
7813b61a
UD
895 {
896 /* If both requests timed out report this. */
897 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
898 return -EAI_AGAIN;
899
900 /* We made requests but they turned out no data. The name
901 is known, though. */
3af48b5b 902 return GAIH_OKIFUNSPEC | -EAI_NODATA;
7813b61a 903 }
46ec036d 904 }
40a55d20 905
d19687d6 906 process_list:
40a55d20 907 if (at->family == AF_UNSPEC)
3af48b5b 908 return GAIH_OKIFUNSPEC | -EAI_NONAME;
46ec036d 909 }
40a55d20
UD
910 else
911 {
7396d844 912 struct gaih_addrtuple *atr;
a0bf6ac7
UD
913 atr = at = __alloca (sizeof (struct gaih_addrtuple));
914 memset (at, '\0', sizeof (struct gaih_addrtuple));
40a55d20 915
28977c2c 916 if (req->ai_family == AF_UNSPEC)
7396d844 917 {
a0bf6ac7
UD
918 at->next = __alloca (sizeof (struct gaih_addrtuple));
919 memset (at->next, '\0', sizeof (struct gaih_addrtuple));
7396d844 920 }
40a55d20 921
28977c2c 922 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
7396d844
UD
923 {
924 at->family = AF_INET6;
925 if ((req->ai_flags & AI_PASSIVE) == 0)
a585ba22 926 memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
7396d844
UD
927 atr = at->next;
928 }
40a55d20 929
28977c2c 930 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
7396d844
UD
931 {
932 atr->family = AF_INET;
933 if ((req->ai_flags & AI_PASSIVE) == 0)
28977c2c 934 atr->addr[0] = htonl (INADDR_LOOPBACK);
7396d844 935 }
46ec036d 936 }
1fb05e3d 937
40a55d20
UD
938 if (pai == NULL)
939 return 0;
46ec036d
UD
940
941 {
46ec036d
UD
942 struct gaih_servtuple *st2;
943 struct gaih_addrtuple *at2 = at;
28977c2c 944 size_t socklen;
85599e53 945 sa_family_t family;
40a55d20 946
f21acc89
UD
947 /*
948 buffer is the size of an unformatted IPv6 address in printable format.
949 */
40a55d20
UD
950 while (at2 != NULL)
951 {
163288fe
UD
952 /* Only the first entry gets the canonical name. */
953 if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
40a55d20 954 {
28977c2c 955 if (canon == NULL)
40a55d20 956 {
28977c2c
UD
957 struct hostent *h = NULL;
958 int herrno;
959 struct hostent th;
960 size_t tmpbuflen = 512;
961 char *tmpbuf = NULL;
40a55d20 962
28977c2c
UD
963 do
964 {
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);
972 }
973 while (rc == ERANGE && herrno == NETDB_INTERNAL);
40a55d20 974
28977c2c 975 if (rc != 0 && herrno == NETDB_INTERNAL)
160d067b 976 {
28977c2c
UD
977 __set_h_errno (herrno);
978 return -EAI_SYSTEM;
160d067b
UD
979 }
980
28977c2c
UD
981 if (h != NULL)
982 canon = h->h_name;
983 else
984 {
b6c0f679 985 assert (orig_name != NULL);
28977c2c
UD
986 /* If the canonical name cannot be determined, use
987 the passed in string. */
b6c0f679 988 canon = orig_name;
28977c2c 989 }
160d067b 990 }
40a55d20 991
de079fee
UD
992#ifdef HAVE_LIBIDN
993 if (req->ai_flags & AI_CANONIDN)
994 {
3a0e90bd
UD
995 int idn_flags = 0;
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;
1000
de079fee 1001 char *out;
28977c2c 1002 int rc = __idna_to_unicode_lzlz (canon, &out, idn_flags);
de079fee
UD
1003 if (rc != IDNA_SUCCESS)
1004 {
1005 if (rc == IDNA_MALLOC_ERROR)
1006 return -EAI_MEMORY;
1007 if (rc == IDNA_DLOPEN_ERROR)
1008 return -EAI_SYSTEM;
1009 return -EAI_IDN_ENCODE;
1010 }
1011 /* In case the output string is the same as the input
b9343764
UD
1012 string no new string has been allocated. Otherwise
1013 make a copy. */
1014 if (out == canon)
1015 goto make_copy;
de079fee 1016 }
b9343764 1017 else
de079fee 1018#endif
b9343764
UD
1019 {
1020#ifdef HAVE_LIBIDN
1021 make_copy:
1022#endif
1023 canon = strdup (canon);
1024 if (canon == NULL)
1025 return -EAI_MEMORY;
1026 }
40a55d20 1027 }
40a55d20 1028
abab6859
UD
1029 family = at2->family;
1030 if (family == AF_INET6)
85599e53 1031 {
85599e53 1032 socklen = sizeof (struct sockaddr_in6);
925c3c5c
UD
1033
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. */
28977c2c 1037 if (got_ipv6
925c3c5c
UD
1038 && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
1039 && IN6_IS_ADDR_V4MAPPED (at2->addr))
1040 goto ignore;
85599e53 1041 }
40a55d20 1042 else
abab6859 1043 socklen = sizeof (struct sockaddr_in);
40a55d20
UD
1044
1045 for (st2 = st; st2 != NULL; st2 = st2->next)
1046 {
a24c5ac4
UD
1047 struct addrinfo *ai;
1048 ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
1049 if (ai == NULL)
e7c8359e
UD
1050 {
1051 free ((char *) canon);
1052 return -EAI_MEMORY;
1053 }
40a55d20 1054
a24c5ac4
UD
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);
b9343764
UD
1061
1062 /* We only add the canonical name once. */
a24c5ac4 1063 ai->ai_canonname = (char *) canon;
b9343764
UD
1064 canon = NULL;
1065
beb32642 1066#ifdef _HAVE_SA_LEN
a24c5ac4 1067 ai->ai_addr->sa_len = socklen;
beb32642 1068#endif /* _HAVE_SA_LEN */
a24c5ac4 1069 ai->ai_addr->sa_family = family;
5a97622d 1070
e7c8359e
UD
1071 /* In case of an allocation error the list must be NULL
1072 terminated. */
1073 ai->ai_next = NULL;
1074
85599e53 1075 if (family == AF_INET6)
40a55d20
UD
1076 {
1077 struct sockaddr_in6 *sin6p =
a24c5ac4 1078 (struct sockaddr_in6 *) ai->ai_addr;
46ec036d 1079
28977c2c 1080 sin6p->sin6_port = st2->port;
40a55d20
UD
1081 sin6p->sin6_flowinfo = 0;
1082 memcpy (&sin6p->sin6_addr,
1083 at2->addr, sizeof (struct in6_addr));
c0bc5f7b 1084 sin6p->sin6_scope_id = at2->scopeid;
40a55d20
UD
1085 }
1086 else
1087 {
1088 struct sockaddr_in *sinp =
a24c5ac4 1089 (struct sockaddr_in *) ai->ai_addr;
28977c2c 1090 sinp->sin_port = st2->port;
40a55d20
UD
1091 memcpy (&sinp->sin_addr,
1092 at2->addr, sizeof (struct in_addr));
1093 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
1094 }
46ec036d 1095
a24c5ac4 1096 pai = &(ai->ai_next);
40a55d20 1097 }
46ec036d 1098
01abbc0f
UD
1099 ++*naddrs;
1100
925c3c5c 1101 ignore:
40a55d20
UD
1102 at2 = at2->next;
1103 }
46ec036d 1104 }
40a55d20 1105 return 0;
46ec036d
UD
1106}
1107
786dcb62 1108#if 0
192c0fa5 1109static const struct gaih gaih[] =
40a55d20
UD
1110 {
1111 { PF_INET6, gaih_inet },
1112 { PF_INET, gaih_inet },
64b7897d 1113#if 0
40a55d20 1114 { PF_LOCAL, gaih_local },
64b7897d 1115#endif
40a55d20
UD
1116 { PF_UNSPEC, NULL }
1117 };
786dcb62 1118#endif
46ec036d 1119
5ddb5bf5
UD
1120struct sort_result
1121{
1122 struct addrinfo *dest_addr;
1123 struct sockaddr_storage source_addr;
d19687d6 1124 uint8_t source_addr_len;
5ddb5bf5 1125 bool got_source_addr;
3af48b5b 1126 uint8_t source_addr_flags;
5ddb5bf5
UD
1127};
1128
1129
1130static int
1131get_scope (const struct sockaddr_storage *ss)
1132{
1133 int scope;
1134 if (ss->ss_family == PF_INET6)
1135 {
1136 const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *) ss;
1137
1138 if (! IN6_IS_ADDR_MULTICAST (&in6->sin6_addr))
1139 {
1140 if (IN6_IS_ADDR_LINKLOCAL (&in6->sin6_addr))
1141 scope = 2;
1142 else if (IN6_IS_ADDR_SITELOCAL (&in6->sin6_addr))
1143 scope = 5;
1144 else
1145 /* XXX Is this the correct default behavior? */
1146 scope = 14;
1147 }
1148 else
1149 scope = in6->sin6_addr.s6_addr[1] & 0xf;
1150 }
1151 else if (ss->ss_family == PF_INET)
1152 {
1153 const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
1154 const uint8_t *addr = (const uint8_t *) &in->sin_addr;
1155
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)
1159 scope = 2;
32c075e1 1160 else if (addr[0] == 10 || (addr[0] == 172 && (addr[1] & 0xf0) == 16)
5ddb5bf5
UD
1161 || (addr[0] == 192 && addr[1] == 168))
1162 scope = 5;
1163 else
1164 scope = 14;
1165 }
1166 else
1167 /* XXX What is a good default? */
1168 scope = 15;
1169
1170 return scope;
1171}
1172
1173
77dd4c3b 1174struct prefixentry
5ddb5bf5
UD
1175{
1176 struct in6_addr prefix;
1177 unsigned int bits;
1178 int val;
77dd4c3b
UD
1179};
1180
1181
1182/* The label table. */
1183static const struct prefixentry *labels;
1184
1185/* Default labels. */
1186static const struct prefixentry default_labels[] =
5ddb5bf5
UD
1187 {
1188 /* See RFC 3484 for the details. */
77dd4c3b
UD
1189 { { .in6_u
1190 = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
5ddb5bf5 1192 128, 0 },
77dd4c3b
UD
1193 { { .in6_u
1194 = { .u6_addr8 = { 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1195 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
5ddb5bf5 1196 16, 2 },
77dd4c3b
UD
1197 { { .in6_u
1198 = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
5ddb5bf5 1200 96, 3 },
77dd4c3b
UD
1201 { { .in6_u
1202 = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1203 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } },
5ddb5bf5 1204 96, 4 },
6e2a7825
UD
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. */
1212 { { .in6_u
1213 = { .u6_addr8 = { 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
1215 10, 5 },
1216 { { .in6_u
1217 = { .u6_addr8 = { 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
1219 7, 6 },
32c075e1
JJ
1220 { { .in6_u
1221 = { .u6_addr8 = { 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
1223 32, 7 },
77dd4c3b
UD
1224 { { .in6_u
1225 = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1226 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
5ddb5bf5
UD
1227 0, 1 }
1228 };
1229
1230
77dd4c3b
UD
1231/* The precedence table. */
1232static const struct prefixentry *precedence;
1233
1234/* The default precedences. */
1235static const struct prefixentry default_precedence[] =
5ddb5bf5
UD
1236 {
1237 /* See RFC 3484 for the details. */
77dd4c3b
UD
1238 { { .in6_u
1239 = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
5ddb5bf5 1241 128, 50 },
77dd4c3b
UD
1242 { { .in6_u
1243 = { .u6_addr8 = { 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
5ddb5bf5 1245 16, 30 },
77dd4c3b
UD
1246 { { .in6_u
1247 = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1248 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
5ddb5bf5 1249 96, 20 },
77dd4c3b
UD
1250 { { .in6_u
1251 = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1252 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } },
6e2a7825 1253 96, 10 },
77dd4c3b
UD
1254 { { .in6_u
1255 = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
5ddb5bf5
UD
1257 0, 40 }
1258 };
1259
1260
1261static int
77dd4c3b
UD
1262match_prefix (const struct sockaddr_storage *ss,
1263 const struct prefixentry *list, int default_val)
5ddb5bf5
UD
1264{
1265 int idx;
1266 struct sockaddr_in6 in6_mem;
1267 const struct sockaddr_in6 *in6;
1268
1269 if (ss->ss_family == PF_INET6)
1270 in6 = (const struct sockaddr_in6 *) ss;
1271 else if (ss->ss_family == PF_INET)
1272 {
1273 const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
1274
1275 /* Convert to IPv6 address. */
1276 in6_mem.sin6_family = PF_INET6;
1277 in6_mem.sin6_port = in->sin_port;
1278 in6_mem.sin6_flowinfo = 0;
1279 if (in->sin_addr.s_addr == htonl (0x7f000001))
1280 in6_mem.sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
1281 else
1282 {
1283 /* Construct a V4-to-6 mapped address. */
1284 memset (&in6_mem.sin6_addr, '\0', sizeof (in6_mem.sin6_addr));
1285 in6_mem.sin6_addr.s6_addr16[5] = 0xffff;
1286 in6_mem.sin6_addr.s6_addr32[3] = in->sin_addr.s_addr;
1287 in6_mem.sin6_scope_id = 0;
1288 }
1289
1290 in6 = &in6_mem;
1291 }
1292 else
1293 return default_val;
1294
1295 for (idx = 0; ; ++idx)
1296 {
1297 unsigned int bits = list[idx].bits;
d4ed7561
UD
1298 const uint8_t *mask = list[idx].prefix.s6_addr;
1299 const uint8_t *val = in6->sin6_addr.s6_addr;
5ddb5bf5 1300
207cce4c 1301 while (bits >= 8)
5ddb5bf5
UD
1302 {
1303 if (*mask != *val)
1304 break;
1305
1306 ++mask;
1307 ++val;
1308 bits -= 8;
1309 }
1310
1311 if (bits < 8)
1312 {
d9a3ae7f 1313 if ((*mask & (0xff00 >> bits)) == (*val & (0xff00 >> bits)))
5ddb5bf5
UD
1314 /* Match! */
1315 break;
1316 }
1317 }
1318
1319 return list[idx].val;
1320}
1321
1322
1323static int
1324get_label (const struct sockaddr_storage *ss)
1325{
1326 /* XXX What is a good default value? */
77dd4c3b 1327 return match_prefix (ss, labels, INT_MAX);
5ddb5bf5
UD
1328}
1329
1330
1331static int
1332get_precedence (const struct sockaddr_storage *ss)
1333{
1334 /* XXX What is a good default value? */
77dd4c3b 1335 return match_prefix (ss, precedence, 0);
5ddb5bf5
UD
1336}
1337
1338
c6bad06a
UD
1339/* Find last bit set in a word. */
1340static int
1341fls (uint32_t a)
1342{
1343 uint32_t mask;
1344 int n = 0;
1345 for (n = 0, mask = 1 << 31; n < 32; mask >>= 1, ++n)
1346 if ((a & mask) != 0)
1347 break;
1348 return n;
1349}
1350
1351
5ddb5bf5
UD
1352static int
1353rfc3484_sort (const void *p1, const void *p2)
1354{
1355 const struct sort_result *a1 = (const struct sort_result *) p1;
1356 const struct sort_result *a2 = (const struct sort_result *) p2;
1357
1358 /* Rule 1: Avoid unusable destinations.
1359 We have the got_source_addr flag set if the destination is reachable. */
1360 if (a1->got_source_addr && ! a2->got_source_addr)
1361 return -1;
1362 if (! a1->got_source_addr && a2->got_source_addr)
1363 return 1;
1364
1365
1366 /* Rule 2: Prefer matching scope. Only interesting if both
1367 destination addresses are IPv6. */
1368 int a1_dst_scope
1369 = get_scope ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1370
1371 int a2_dst_scope
1372 = get_scope ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1373
1374 if (a1->got_source_addr)
1375 {
1376 int a1_src_scope = get_scope (&a1->source_addr);
1377 int a2_src_scope = get_scope (&a2->source_addr);
1378
1379 if (a1_dst_scope == a1_src_scope && a2_dst_scope != a2_src_scope)
1380 return -1;
1381 if (a1_dst_scope != a1_src_scope && a2_dst_scope == a2_src_scope)
1382 return 1;
1383 }
1384
1385
3af48b5b
UD
1386 /* Rule 3: Avoid deprecated addresses. */
1387 if (a1->got_source_addr)
1388 {
1389 if (!(a1->source_addr_flags & in6ai_deprecated)
1390 && (a2->source_addr_flags & in6ai_deprecated))
1391 return -1;
1392 if ((a1->source_addr_flags & in6ai_deprecated)
1393 && !(a2->source_addr_flags & in6ai_deprecated))
1394 return 1;
1395 }
5ddb5bf5 1396
457b559e
UD
1397 /* Rule 4: Prefer home addresses. */
1398 if (a1->got_source_addr)
1399 {
1400 if (!(a1->source_addr_flags & in6ai_homeaddress)
1401 && (a2->source_addr_flags & in6ai_homeaddress))
4a85a8ee 1402 return 1;
457b559e
UD
1403 if ((a1->source_addr_flags & in6ai_homeaddress)
1404 && !(a2->source_addr_flags & in6ai_homeaddress))
4a85a8ee 1405 return -1;
457b559e 1406 }
5ddb5bf5
UD
1407
1408 /* Rule 5: Prefer matching label. */
1409 if (a1->got_source_addr)
1410 {
1411 int a1_dst_label
1412 = get_label ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1413 int a1_src_label = get_label (&a1->source_addr);
1414
1415 int a2_dst_label
1416 = get_label ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1417 int a2_src_label = get_label (&a2->source_addr);
1418
1419 if (a1_dst_label == a1_src_label && a2_dst_label != a2_src_label)
1420 return -1;
1421 if (a1_dst_label != a1_src_label && a2_dst_label == a2_src_label)
1422 return 1;
1423 }
1424
1425
1426 /* Rule 6: Prefer higher precedence. */
1427 int a1_prec
1428 = get_precedence ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1429 int a2_prec
1430 = get_precedence ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1431
1432 if (a1_prec > a2_prec)
1433 return -1;
1434 if (a1_prec < a2_prec)
1435 return 1;
1436
1437
3af48b5b
UD
1438 /* Rule 7: Prefer native transport. */
1439 if (a1->got_source_addr)
1440 {
1441 if (!(a1->source_addr_flags & in6ai_temporary)
4a85a8ee 1442 && (a2->source_addr_flags & in6ai_temporary))
3af48b5b
UD
1443 return -1;
1444 if ((a1->source_addr_flags & in6ai_temporary)
4a85a8ee
UD
1445 && !(a2->source_addr_flags & in6ai_temporary))
1446 return 1;
3af48b5b
UD
1447
1448 /* XXX Do we need to check anything beside temporary addresses? */
1449 }
5ddb5bf5
UD
1450
1451
1452 /* Rule 8: Prefer smaller scope. */
1453 if (a1_dst_scope < a2_dst_scope)
1454 return -1;
1455 if (a1_dst_scope > a2_dst_scope)
1456 return 1;
1457
1458
1459 /* Rule 9: Use longest matching prefix. */
1460 if (a1->got_source_addr
1461 && a1->dest_addr->ai_family == a2->dest_addr->ai_family)
1462 {
1463 int bit1 = 0;
1464 int bit2 = 0;
1465
1466 if (a1->dest_addr->ai_family == PF_INET)
1467 {
1468 assert (a1->source_addr.ss_family == PF_INET);
1469 assert (a2->source_addr.ss_family == PF_INET);
1470
1471 struct sockaddr_in *in1_dst;
1472 struct sockaddr_in *in1_src;
1473 struct sockaddr_in *in2_dst;
1474 struct sockaddr_in *in2_src;
1475
1476 in1_dst = (struct sockaddr_in *) a1->dest_addr->ai_addr;
1477 in1_src = (struct sockaddr_in *) &a1->source_addr;
1478 in2_dst = (struct sockaddr_in *) a2->dest_addr->ai_addr;
1479 in2_src = (struct sockaddr_in *) &a2->source_addr;
1480
c6bad06a
UD
1481 bit1 = fls (ntohl (in1_dst->sin_addr.s_addr
1482 ^ in1_src->sin_addr.s_addr));
1483 bit2 = fls (ntohl (in2_dst->sin_addr.s_addr
1484 ^ in2_src->sin_addr.s_addr));
5ddb5bf5
UD
1485 }
1486 else if (a1->dest_addr->ai_family == PF_INET6)
1487 {
1488 assert (a1->source_addr.ss_family == PF_INET6);
1489 assert (a2->source_addr.ss_family == PF_INET6);
1490
1491 struct sockaddr_in6 *in1_dst;
1492 struct sockaddr_in6 *in1_src;
1493 struct sockaddr_in6 *in2_dst;
1494 struct sockaddr_in6 *in2_src;
1495
1496 in1_dst = (struct sockaddr_in6 *) a1->dest_addr->ai_addr;
1497 in1_src = (struct sockaddr_in6 *) &a1->source_addr;
1498 in2_dst = (struct sockaddr_in6 *) a2->dest_addr->ai_addr;
1499 in2_src = (struct sockaddr_in6 *) &a2->source_addr;
1500
1501 int i;
1502 for (i = 0; i < 4; ++i)
1503 if (in1_dst->sin6_addr.s6_addr32[i]
1504 != in1_src->sin6_addr.s6_addr32[i]
1505 || (in2_dst->sin6_addr.s6_addr32[i]
1506 != in2_src->sin6_addr.s6_addr32[i]))
1507 break;
1508
1509 if (i < 4)
1510 {
c6bad06a
UD
1511 bit1 = fls (ntohl (in1_dst->sin6_addr.s6_addr32[i]
1512 ^ in1_src->sin6_addr.s6_addr32[i]));
1513 bit2 = fls (ntohl (in2_dst->sin6_addr.s6_addr32[i]
1514 ^ in2_src->sin6_addr.s6_addr32[i]));
5ddb5bf5
UD
1515 }
1516 }
1517
1518 if (bit1 > bit2)
1519 return -1;
1520 if (bit1 < bit2)
1521 return 1;
1522 }
1523
1524
1525 /* Rule 10: Otherwise, leave the order unchanged. */
1526 return 0;
1527}
1528
1529
3af48b5b
UD
1530static int
1531in6aicmp (const void *p1, const void *p2)
1532{
1533 struct in6addrinfo *a1 = (struct in6addrinfo *) p1;
1534 struct in6addrinfo *a2 = (struct in6addrinfo *) p2;
1535
1536 return memcmp (a1->addr, a2->addr, sizeof (a1->addr));
1537}
1538
1539
77dd4c3b
UD
1540/* Name of the config file for RFC 3484 sorting (for now). */
1541#define GAICONF_FNAME "/etc/gai.conf"
1542
1543
1544/* Nozero if we are supposed to reload the config file automatically
1545 whenever it changed. */
1546static int gaiconf_reload_flag;
1547
1548/* Last modification time. */
1549static struct timespec gaiconf_mtime;
1550
1551
1552libc_freeres_fn(fini)
1553{
1554 if (labels != default_labels)
1555 {
1556 const struct prefixentry *old = labels;
1557 labels = default_labels;
1558 free ((void *) old);
1559 }
1560
1561 if (precedence != default_precedence)
1562 {
1563 const struct prefixentry *old = precedence;
1564 precedence = default_precedence;
1565 free ((void *) old);
1566 }
1567}
1568
1569
1570struct prefixlist
1571{
1572 struct prefixentry entry;
1573 struct prefixlist *next;
1574};
1575
1576
1577static void
1578free_prefixlist (struct prefixlist *list)
1579{
1580 while (list != NULL)
1581 {
1582 struct prefixlist *oldp = list;
1583 list = list->next;
1584 free (oldp);
1585 }
1586}
1587
1588
1589static int
1590prefixcmp (const void *p1, const void *p2)
1591{
1592 const struct prefixentry *e1 = (const struct prefixentry *) p1;
1593 const struct prefixentry *e2 = (const struct prefixentry *) p2;
1594
1595 if (e1->bits < e2->bits)
1596 return 1;
1597 if (e1->bits == e2->bits)
1598 return 0;
1599 return -1;
1600}
1601
1602
1603static void
1604gaiconf_init (void)
1605{
1606 struct prefixlist *labellist = NULL;
1607 size_t nlabellist = 0;
1608 bool labellist_nullbits = false;
1609 struct prefixlist *precedencelist = NULL;
1610 size_t nprecedencelist = 0;
1611 bool precedencelist_nullbits = false;
1612
1613 FILE *fp = fopen (GAICONF_FNAME, "rc");
1614 if (fp != NULL)
1615 {
1616 struct stat64 st;
1617 if (__fxstat64 (_STAT_VER, fileno (fp), &st) != 0)
1618 {
1619 fclose (fp);
1620 goto no_file;
1621 }
1622
1623 char *line = NULL;
1624 size_t linelen = 0;
1625
1626 __fsetlocking (fp, FSETLOCKING_BYCALLER);
1627
1628 while (!feof_unlocked (fp))
1629 {
1630 ssize_t n = __getline (&line, &linelen, fp);
1631 if (n <= 0)
1632 break;
1633
1634 /* Handle comments. No escaping possible so this is easy. */
1635 char *cp = strchr (line, '#');
1636 if (cp != NULL)
1637 *cp = '\0';
1638
1639 cp = line;
1640 while (isspace (*cp))
1641 ++cp;
1642
1643 char *cmd = cp;
1644 while (*cp != '\0' && !isspace (*cp))
1645 ++cp;
1646 size_t cmdlen = cp - cmd;
1647
1648 if (*cp != '\0')
1649 *cp++ = '\0';
1650 while (isspace (*cp))
1651 ++cp;
1652
1653 char *val1 = cp;
1654 while (*cp != '\0' && !isspace (*cp))
1655 ++cp;
1656 size_t val1len = cp - cmd;
1657
1658 /* We always need at least two values. */
1659 if (val1len == 0)
1660 continue;
1661
1662 if (*cp != '\0')
1663 *cp++ = '\0';
1664 while (isspace (*cp))
1665 ++cp;
1666
1667 char *val2 = cp;
1668 while (*cp != '\0' && !isspace (*cp))
1669 ++cp;
1670
1671 /* Ignore the rest of the line. */
1672 *cp = '\0';
1673
1674 struct prefixlist **listp;
1675 size_t *lenp;
1676 bool *nullbitsp;
1677 switch (cmdlen)
1678 {
1679 case 5:
1680 if (strcmp (cmd, "label") == 0)
1681 {
1682 struct in6_addr prefix;
ecc68568 1683 unsigned long int bits;
77dd4c3b
UD
1684 unsigned long int val;
1685 char *endp;
1686
1687 listp = &labellist;
1688 lenp = &nlabellist;
1689 nullbitsp = &labellist_nullbits;
1690
1691 new_elem:
ecc68568 1692 bits = 128;
77dd4c3b
UD
1693 __set_errno (0);
1694 cp = strchr (val1, '/');
1695 if (cp != NULL)
1696 *cp++ = '\0';
1697 if (inet_pton (AF_INET6, val1, &prefix)
1698 && (cp == NULL
1699 || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX
1700 || errno != ERANGE)
1701 && *endp == '\0'
1702 && bits <= INT_MAX
1703 && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX
1704 || errno != ERANGE)
1705 && *endp == '\0'
1706 && val <= INT_MAX)
1707 {
1708 struct prefixlist *newp = malloc (sizeof (*newp));
1709 if (newp == NULL)
1710 {
1711 free (line);
1712 fclose (fp);
1713 goto no_file;
1714 }
1715
1716 memcpy (&newp->entry.prefix, &prefix, sizeof (prefix));
1717 newp->entry.bits = bits;
1718 newp->entry.val = val;
1719 newp->next = *listp;
1720 *listp = newp;
1721 ++*lenp;
1722 *nullbitsp |= bits == 0;
1723 }
1724 }
1725 break;
1726
1727 case 6:
1728 if (strcmp (cmd, "reload") == 0)
1729 gaiconf_reload_flag = strcmp (val1, "yes") == 0;
1730 break;
1731
1732 case 10:
1733 if (strcmp (cmd, "precedence") == 0)
1734 {
1735 listp = &precedencelist;
1736 lenp = &nprecedencelist;
1737 nullbitsp = &precedencelist_nullbits;
1738 goto new_elem;
1739 }
1740 break;
1741 }
1742 }
1743
1744 free (line);
1745
1746 fclose (fp);
1747
1748 /* Create the array for the labels. */
1749 struct prefixentry *new_labels;
1750 if (nlabellist > 0)
1751 {
1752 if (!labellist_nullbits)
1753 ++nlabellist;
1754 new_labels = malloc (nlabellist * sizeof (*new_labels));
1755 if (new_labels == NULL)
1756 goto no_file;
1757
1758 int i = nlabellist;
1759 if (!labellist_nullbits)
1760 {
1761 --i;
1762 memset (&new_labels[i].prefix, '\0', sizeof (struct in6_addr));
1763 new_labels[i].bits = 0;
1764 new_labels[i].val = 1;
1765 }
1766
1767 struct prefixlist *l = labellist;
1768 while (i-- > 0)
1769 {
1770 new_labels[i] = l->entry;
1771 l = l->next;
1772 }
1773 free_prefixlist (labellist);
1774
1775 /* Sort the entries so that the most specific ones are at
1776 the beginning. */
1777 qsort (new_labels, nlabellist, sizeof (*new_labels), prefixcmp);
1778 }
1779 else
1780 new_labels = (struct prefixentry *) default_labels;
1781
1782 struct prefixentry *new_precedence;
1783 if (nprecedencelist > 0)
1784 {
1785 if (!precedencelist_nullbits)
1786 ++nprecedencelist;
1787 new_precedence = malloc (nprecedencelist * sizeof (*new_precedence));
1788 if (new_precedence == NULL)
1789 {
1790 if (new_labels != default_labels)
1791 free (new_labels);
1792 goto no_file;
1793 }
1794
1795 int i = nprecedencelist;
1796 if (!precedencelist_nullbits)
1797 {
1798 --i;
1799 memset (&new_precedence[i].prefix, '\0',
1800 sizeof (struct in6_addr));
1801 new_precedence[i].bits = 0;
1802 new_precedence[i].val = 40;
1803 }
1804
1805 struct prefixlist *l = precedencelist;
1806 while (i-- > 0)
1807 {
1808 new_precedence[i] = l->entry;
1809 l = l->next;
1810 }
1811 free_prefixlist (precedencelist);
1812
1813 /* Sort the entries so that the most specific ones are at
1814 the beginning. */
1815 qsort (new_precedence, nprecedencelist, sizeof (*new_labels),
1816 prefixcmp);
1817 }
1818 else
1819 new_precedence = (struct prefixentry *) default_precedence;
1820
1821 /* Now we are ready to replace the values. */
1822 const struct prefixentry *old = labels;
1823 labels = new_labels;
1824 if (old != default_labels)
1825 free ((void *) old);
1826
1827 old = precedence;
1828 precedence = new_precedence;
1829 if (old != default_precedence)
1830 free ((void *) old);
1831
1832 gaiconf_mtime = st.st_mtim;
1833 }
1834 else
1835 {
1836 no_file:
1837 free_prefixlist (labellist);
1838 free_prefixlist (precedencelist);
1839
1840 /* If we previously read the file but it is gone now, free the
1841 old data and use the builtin one. Leave the reload flag
1842 alone. */
1843 fini ();
1844 }
1845}
1846
1847
1848static void
1849gaiconf_reload (void)
1850{
1851 struct stat64 st;
1852 if (__xstat64 (_STAT_VER, GAICONF_FNAME, &st) != 0
1853 || memcmp (&st.st_mtim, &gaiconf_mtime, sizeof (gaiconf_mtime)) != 0)
1854 gaiconf_init ();
1855}
1856
1857
40a55d20
UD
1858int
1859getaddrinfo (const char *name, const char *service,
1860 const struct addrinfo *hints, struct addrinfo **pai)
46ec036d 1861{
786dcb62 1862 int i = 0, last_i = 0;
5ddb5bf5 1863 int nresults = 0;
786dcb62 1864 struct addrinfo *p = NULL;
46ec036d 1865 struct gaih_service gaih_service, *pservice;
925c3c5c 1866 struct addrinfo local_hints;
46ec036d 1867
40a55d20 1868 if (name != NULL && name[0] == '*' && name[1] == 0)
1fb05e3d
UD
1869 name = NULL;
1870
40a55d20 1871 if (service != NULL && service[0] == '*' && service[1] == 0)
1fb05e3d
UD
1872 service = NULL;
1873
40a55d20 1874 if (name == NULL && service == NULL)
46ec036d
UD
1875 return EAI_NONAME;
1876
40a55d20
UD
1877 if (hints == NULL)
1878 hints = &default_hints;
46ec036d 1879
925c3c5c
UD
1880 if (hints->ai_flags
1881 & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|AI_ADDRCONFIG|AI_V4MAPPED
e2fd3cbe 1882#ifdef HAVE_LIBIDN
3a0e90bd
UD
1883 |AI_IDN|AI_CANONIDN|AI_IDN_ALLOW_UNASSIGNED
1884 |AI_IDN_USE_STD3_ASCII_RULES
e2fd3cbe 1885#endif
c1d98085 1886 |AI_NUMERICSERV|AI_ALL))
46ec036d
UD
1887 return EAI_BADFLAGS;
1888
06877a37 1889 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
46ec036d
UD
1890 return EAI_BADFLAGS;
1891
cf6ada44 1892 struct in6addrinfo *in6ai = NULL;
3af48b5b
UD
1893 size_t in6ailen;
1894 bool seen_ipv4 = false;
1895 bool seen_ipv6 = false;
1896 /* We might need information about what kind of interfaces are available.
1897 But even if AI_ADDRCONFIG is not used, if the user requested IPv6
1898 addresses we have to know whether an address is deprecated or
1899 temporary. */
1900 if ((hints->ai_flags & AI_ADDRCONFIG) || hints->ai_family == PF_UNSPEC
1901 || hints->ai_family == PF_INET6)
1902 /* Determine whether we have IPv4 or IPv6 interfaces or both. We
1903 cannot cache the results since new interfaces could be added at
1904 any time. */
1905 __check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen);
1906
925c3c5c
UD
1907 if (hints->ai_flags & AI_ADDRCONFIG)
1908 {
925c3c5c 1909 /* Now make a decision on what we return, if anything. */
c1d98085 1910 if (hints->ai_family == PF_UNSPEC && (seen_ipv4 || seen_ipv6))
925c3c5c
UD
1911 {
1912 /* If we haven't seen both IPv4 and IPv6 interfaces we can
1913 narrow down the search. */
1914 if (! seen_ipv4 || ! seen_ipv6)
1915 {
1916 local_hints = *hints;
1917 local_hints.ai_family = seen_ipv4 ? PF_INET : PF_INET6;
1918 hints = &local_hints;
1919 }
1920 }
1921 else if ((hints->ai_family == PF_INET && ! seen_ipv4)
1922 || (hints->ai_family == PF_INET6 && ! seen_ipv6))
3af48b5b
UD
1923 {
1924 /* We cannot possibly return a valid answer. */
1925 free (in6ai);
1926 return EAI_NONAME;
1927 }
925c3c5c
UD
1928 }
1929
40a55d20
UD
1930 if (service && service[0])
1931 {
1932 char *c;
1933 gaih_service.name = service;
1934 gaih_service.num = strtoul (gaih_service.name, &c, 10);
c1d98085
UD
1935 if (*c != '\0')
1936 {
1937 if (hints->ai_flags & AI_NUMERICSERV)
3af48b5b
UD
1938 {
1939 free (in6ai);
1940 return EAI_NONAME;
1941 }
c1d98085
UD
1942
1943 gaih_service.num = -1;
1944 }
ca225a41 1945
40a55d20
UD
1946 pservice = &gaih_service;
1947 }
1948 else
46ec036d
UD
1949 pservice = NULL;
1950
786dcb62 1951 struct addrinfo **end;
1fb05e3d
UD
1952 if (pai)
1953 end = &p;
1954 else
1955 end = NULL;
1956
01abbc0f 1957 unsigned int naddrs = 0;
786dcb62
UD
1958#if 0
1959 /* If we would support more protocols than just IPv4 and IPv6 we
1960 would iterate over a table with appropriate callback functions.
1961 Since we currently only handle IPv4 and IPv6 this is not
1962 necessary. */
1963 const struct gaih *g = gaih;
1964 const struct gaih *pg = NULL;
1965 int j = 0;
40a55d20
UD
1966 while (g->gaih)
1967 {
7396d844 1968 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
40a55d20
UD
1969 {
1970 j++;
7396d844 1971 if (pg == NULL || pg->gaih != g->gaih)
40a55d20
UD
1972 {
1973 pg = g;
01abbc0f 1974 i = g->gaih (name, pservice, hints, end, &naddrs);
7396d844 1975 if (i != 0)
40a55d20 1976 {
a0bf6ac7
UD
1977 /* EAI_NODATA is a more specific result as it says that
1978 we found a result but it is not usable. */
1979 if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA))
1980 last_i = i;
1981
7396d844 1982 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
160d067b
UD
1983 {
1984 ++g;
1985 continue;
1986 }
40a55d20 1987
160d067b 1988 freeaddrinfo (p);
3af48b5b 1989 free (in6ai);
40a55d20 1990
7396d844 1991 return -(i & GAIH_EAI);
40a55d20
UD
1992 }
1993 if (end)
5ddb5bf5
UD
1994 while (*end)
1995 {
1996 end = &((*end)->ai_next);
1997 ++nresults;
1998 }
40a55d20 1999 }
46ec036d 2000 }
40a55d20 2001 ++g;
46ec036d 2002 }
46ec036d 2003
40a55d20 2004 if (j == 0)
3af48b5b
UD
2005 {
2006 free (in6ai);
2007 return EAI_FAMILY;
2008 }
786dcb62
UD
2009#else
2010 if (hints->ai_family == AF_UNSPEC || hints->ai_family == AF_INET
2011 || hints->ai_family == AF_INET6)
2012 {
2013 last_i = gaih_inet (name, pservice, hints, end, &naddrs);
2014 if (last_i != 0)
2015 {
2016 freeaddrinfo (p);
2017 free (in6ai);
2018
105a492d 2019 return -(last_i & GAIH_EAI);
786dcb62
UD
2020 }
2021 if (end)
2022 while (*end)
2023 {
2024 end = &((*end)->ai_next);
2025 ++nresults;
2026 }
2027 }
2028 else
2029 {
2030 free (in6ai);
2031 return EAI_FAMILY;
2032 }
2033#endif
46ec036d 2034
01abbc0f 2035 if (naddrs > 1)
5ddb5bf5 2036 {
77dd4c3b
UD
2037 /* Read the config file. */
2038 __libc_once_define (static, once);
2039 __typeof (once) old_once = once;
2040 __libc_once (once, gaiconf_init);
2041 if (old_once && gaiconf_reload_flag)
2042 gaiconf_reload ();
2043
5ddb5bf5
UD
2044 /* Sort results according to RFC 3484. */
2045 struct sort_result results[nresults];
2046 struct addrinfo *q;
d19687d6 2047 struct addrinfo *last = NULL;
c7fa647a 2048 char *canonname = NULL;
5ddb5bf5 2049
3af48b5b
UD
2050 /* If we have information about deprecated and temporary address
2051 sort the array now. */
2052 if (in6ai != NULL)
2053 qsort (in6ai, in6ailen, sizeof (*in6ai), in6aicmp);
2054
d19687d6 2055 for (i = 0, q = p; q != NULL; ++i, last = q, q = q->ai_next)
5ddb5bf5
UD
2056 {
2057 results[i].dest_addr = q;
2058 results[i].got_source_addr = false;
2059
007a3ddc 2060 /* If we just looked up the address for a different
d19687d6
UD
2061 protocol, reuse the result. */
2062 if (last != NULL && last->ai_addrlen == q->ai_addrlen
2063 && memcmp (last->ai_addr, q->ai_addr, q->ai_addrlen) == 0)
5ddb5bf5 2064 {
d19687d6
UD
2065 memcpy (&results[i].source_addr, &results[i - 1].source_addr,
2066 results[i - 1].source_addr_len);
2067 results[i].source_addr_len = results[i - 1].source_addr_len;
2068 results[i].got_source_addr = results[i - 1].got_source_addr;
3af48b5b 2069 results[i].source_addr_flags = results[i - 1].source_addr_flags;
d19687d6
UD
2070 }
2071 else
2072 {
3af48b5b
UD
2073 results[i].source_addr_flags = 0;
2074
007a3ddc
UD
2075 /* We overwrite the type with SOCK_DGRAM since we do not
2076 want connect() to connect to the other side. If we
2077 cannot determine the source address remember this
2078 fact. */
d19687d6 2079 int fd = __socket (q->ai_family, SOCK_DGRAM, IPPROTO_IP);
007a3ddc
UD
2080 socklen_t sl = sizeof (results[i].source_addr);
2081 if (fd != -1
2082 && __connect (fd, q->ai_addr, q->ai_addrlen) == 0
2083 && __getsockname (fd,
2084 (struct sockaddr *) &results[i].source_addr,
2085 &sl) == 0)
d19687d6 2086 {
007a3ddc
UD
2087 results[i].source_addr_len = sl;
2088 results[i].got_source_addr = true;
3af48b5b
UD
2089
2090 if (q->ai_family == PF_INET6 && in6ai != NULL)
2091 {
32c075e1
JJ
2092 /* See whether the address is the list of deprecated
2093 or temporary addresses. */
3af48b5b 2094 struct in6addrinfo tmp;
32c075e1 2095 memcpy (tmp.addr, q->ai_addr, IN6ADDRSZ);
3af48b5b
UD
2096
2097 struct in6addrinfo *found
2098 = bsearch (&tmp, in6ai, in6ailen, sizeof (*in6ai),
2099 in6aicmp);
2100 if (found != NULL)
2101 results[i].source_addr_flags = found->flags;
2102 }
d19687d6 2103 }
007a3ddc
UD
2104 else
2105 /* Just make sure that if we have to process the same
2106 address again we do not copy any memory. */
2107 results[i].source_addr_len = 0;
2108
2109 if (fd != -1)
2110 close_not_cancel_no_status (fd);
5ddb5bf5 2111 }
c7fa647a
UD
2112
2113 /* Remember the canonical name. */
2114 if (q->ai_canonname != NULL)
2115 {
2116 assert (canonname == NULL);
2117 canonname = q->ai_canonname;
2118 q->ai_canonname = NULL;
2119 }
5ddb5bf5
UD
2120 }
2121
2122 /* We got all the source addresses we can get, now sort using
2123 the information. */
2124 qsort (results, nresults, sizeof (results[0]), rfc3484_sort);
2125
2126 /* Queue the results up as they come out of sorting. */
2127 q = p = results[0].dest_addr;
2128 for (i = 1; i < nresults; ++i)
2129 q = q->ai_next = results[i].dest_addr;
2130 q->ai_next = NULL;
c7fa647a
UD
2131
2132 /* Fill in the canonical name into the new first entry. */
2133 p->ai_canonname = canonname;
5ddb5bf5
UD
2134 }
2135
3af48b5b
UD
2136 free (in6ai);
2137
40a55d20
UD
2138 if (p)
2139 {
2140 *pai = p;
2141 return 0;
2142 }
46ec036d 2143
a0bf6ac7 2144 if (pai == NULL && last_i == 0)
1fb05e3d
UD
2145 return 0;
2146
a0bf6ac7 2147 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
46ec036d 2148}
9b0b40d3 2149libc_hidden_def (getaddrinfo)
46ec036d 2150
2f7f7bc6
UD
2151static_link_warning (getaddrinfo)
2152
40a55d20
UD
2153void
2154freeaddrinfo (struct addrinfo *ai)
46ec036d
UD
2155{
2156 struct addrinfo *p;
2157
40a55d20
UD
2158 while (ai != NULL)
2159 {
2160 p = ai;
2161 ai = ai->ai_next;
b9343764 2162 free (p->ai_canonname);
40a55d20
UD
2163 free (p);
2164 }
46ec036d 2165}
9b0b40d3 2166libc_hidden_def (freeaddrinfo)