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