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