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