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