]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/posix/getaddrinfo.c
nss: fix nss_database_lookup2's alternate handling [BZ #27416]
[thirdparty/glibc.git] / sysdeps / posix / getaddrinfo.c
CommitLineData
cd065b68 1/* Host and service name lookups using Name Service Switch modules.
2b778ceb 2 Copyright (C) 1996-2021 Free Software Foundation, Inc.
cd065b68
FW
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
cd065b68 18
46ec036d
UD
19/* The Inner Net License, Version 2.00
20
21 The author(s) grant permission for redistribution and use in source and
22binary forms, with or without modification, of the software and documentation
23provided that the following conditions are met:
24
250. If you receive a version of the software that is specifically labelled
26 as not being for redistribution (check the version message and/or README),
27 you are not permitted to redistribute that version of the software in any
28 way or form.
291. All terms of the all other applicable copyrights and licenses must be
30 followed.
312. Redistributions of source code must retain the authors' copyright
32 notice(s), this list of conditions, and the following disclaimer.
333. Redistributions in binary form must reproduce the authors' copyright
34 notice(s), this list of conditions, and the following disclaimer in the
35 documentation and/or other materials provided with the distribution.
aeb25823 364. [The copyright holder has authorized the removal of this clause.]
46ec036d
UD
375. Neither the name(s) of the author(s) nor the names of its contributors
38 may be used to endorse or promote products derived from this software
39 without specific prior written permission.
40
41THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
42EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
43WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
45DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
48ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51
52 If these license terms cause you a real problem, contact the author. */
53
54/* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
55
c0bc5f7b 56#include <assert.h>
77dd4c3b 57#include <ctype.h>
c0bc5f7b 58#include <errno.h>
925c3c5c 59#include <ifaddrs.h>
c0bc5f7b 60#include <netdb.h>
1eb946b9 61#include <nss.h>
b76e0659 62#include <resolv/resolv-internal.h>
352f4ff9 63#include <resolv/resolv_context.h>
f24dca48 64#include <stdbool.h>
c0bc5f7b 65#include <stdio.h>
77dd4c3b 66#include <stdio_ext.h>
46ec036d 67#include <stdlib.h>
c0bc5f7b 68#include <string.h>
e054f494 69#include <stdint.h>
c0bc5f7b 70#include <arpa/inet.h>
77dd4c3b 71#include <net/if.h>
a334319f 72#include <netinet/in.h>
77dd4c3b
UD
73#include <sys/socket.h>
74#include <sys/stat.h>
c0bc5f7b
UD
75#include <sys/types.h>
76#include <sys/un.h>
77#include <sys/utsname.h>
77dd4c3b 78#include <unistd.h>
218d76e0 79#include <nsswitch.h>
ec999b8e 80#include <libc-lock.h>
5ddb5bf5 81#include <not-cancel.h>
d19687d6 82#include <nscd/nscd-client.h>
62417d7e 83#include <nscd/nscd_proto.h>
cd065b68 84#include <scratch_buffer.h>
80d8cb91 85#include <inet/net-internal.h>
1fb05e3d 86
7f9f1ecb
FW
87/* Former AI_IDN_ALLOW_UNASSIGNED and AI_IDN_USE_STD3_ASCII_RULES
88 flags, now ignored. */
89#define DEPRECATED_AI_IDN 0x300
e2fd3cbe 90
7fc03cf3
JM
91#if IS_IN (libc)
92# define feof_unlocked(fp) __feof_unlocked (fp)
93#endif
94
40a55d20
UD
95struct gaih_service
96 {
97 const char *name;
98 int num;
99 };
46ec036d 100
40a55d20
UD
101struct gaih_servtuple
102 {
103 struct gaih_servtuple *next;
104 int socktype;
105 int protocol;
106 int port;
107 };
46ec036d 108
3e2d61a3 109static const struct gaih_servtuple nullserv;
46ec036d 110
46ec036d 111
40a55d20
UD
112struct gaih_typeproto
113 {
114 int socktype;
115 int protocol;
372bfcac
UD
116 uint8_t protoflag;
117 bool defaultflag;
118 char name[8];
40a55d20 119 };
46ec036d 120
f3ac48d0
UD
121/* Values for `protoflag'. */
122#define GAI_PROTO_NOSERVICE 1
85599e53 123#define GAI_PROTO_PROTOANY 2
f3ac48d0 124
3e2d61a3 125static const struct gaih_typeproto gaih_inet_typeproto[] =
40a55d20 126{
372bfcac
UD
127 { 0, 0, 0, false, "" },
128 { SOCK_STREAM, IPPROTO_TCP, 0, true, "tcp" },
129 { SOCK_DGRAM, IPPROTO_UDP, 0, true, "udp" },
130#if defined SOCK_DCCP && defined IPPROTO_DCCP
131 { SOCK_DCCP, IPPROTO_DCCP, 0, false, "dccp" },
132#endif
133#ifdef IPPROTO_UDPLITE
134 { SOCK_DGRAM, IPPROTO_UDPLITE, 0, false, "udplite" },
18a74157
UD
135#endif
136#ifdef IPPROTO_SCTP
137 { SOCK_STREAM, IPPROTO_SCTP, 0, false, "sctp" },
138 { SOCK_SEQPACKET, IPPROTO_SCTP, 0, false, "sctp" },
372bfcac
UD
139#endif
140 { SOCK_RAW, 0, GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE, true, "raw" },
141 { 0, 0, 0, false, "" }
46ec036d
UD
142};
143
3e2d61a3 144static const struct addrinfo default_hints =
925c3c5c
UD
145 {
146 .ai_flags = AI_DEFAULT,
147 .ai_family = PF_UNSPEC,
148 .ai_socktype = 0,
149 .ai_protocol = 0,
150 .ai_addrlen = 0,
151 .ai_addr = NULL,
152 .ai_canonname = NULL,
153 .ai_next = NULL
154 };
40a55d20
UD
155
156
40a55d20 157static int
3e2d61a3 158gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
cd065b68
FW
159 const struct addrinfo *req, struct gaih_servtuple *st,
160 struct scratch_buffer *tmpbuf)
46ec036d
UD
161{
162 struct servent *s;
993b3242 163 struct servent ts;
40a55d20
UD
164 int r;
165
166 do
993b3242 167 {
cd065b68
FW
168 r = __getservbyname_r (servicename, tp->name, &ts,
169 tmpbuf->data, tmpbuf->length, &s);
a0bf6ac7 170 if (r != 0 || s == NULL)
993b3242 171 {
a0bf6ac7 172 if (r == ERANGE)
cd065b68
FW
173 {
174 if (!scratch_buffer_grow (tmpbuf))
175 return -EAI_MEMORY;
176 }
40a55d20 177 else
639a0ef8 178 return -EAI_SERVICE;
993b3242
UD
179 }
180 }
40a55d20 181 while (r);
993b3242 182
238ae1eb
UD
183 st->next = NULL;
184 st->socktype = tp->socktype;
85599e53
UD
185 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
186 ? req->ai_protocol : tp->protocol);
238ae1eb 187 st->port = s->s_port;
46ec036d
UD
188
189 return 0;
190}
191
4ab2ab03
FW
192/* Convert struct hostent to a list of struct gaih_addrtuple objects.
193 h_name is not copied, and the struct hostent object must not be
5cf88a83
DB
194 deallocated prematurely. *RESULT must be NULL or a pointer to a
195 linked-list. The new addresses are appended at the end. */
4ab2ab03
FW
196static bool
197convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
198 int family,
199 struct hostent *h,
200 struct gaih_addrtuple **result)
201{
5cf88a83
DB
202 while (*result)
203 result = &(*result)->next;
4ab2ab03
FW
204
205 /* Count the number of addresses in h->h_addr_list. */
206 size_t count = 0;
207 for (char **p = h->h_addr_list; *p != NULL; ++p)
208 ++count;
209
210 /* Report no data if no addresses are available, or if the incoming
211 address size is larger than what we can store. */
212 if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
213 return true;
214
215 struct gaih_addrtuple *array = calloc (count, sizeof (*array));
216 if (array == NULL)
217 return false;
218
219 for (size_t i = 0; i < count; ++i)
220 {
221 if (family == AF_INET && req->ai_family == AF_INET6)
222 {
223 /* Perform address mapping. */
224 array[i].family = AF_INET6;
225 memcpy(array[i].addr + 3, h->h_addr_list[i], sizeof (uint32_t));
226 array[i].addr[2] = htonl (0xffff);
227 }
228 else
229 {
230 array[i].family = family;
231 memcpy (array[i].addr, h->h_addr_list[i], h->h_length);
232 }
233 array[i].next = array + i + 1;
234 }
235 array[0].name = h->h_name;
236 array[count - 1].next = NULL;
237
238 *result = array;
239 return true;
240}
241
925c3c5c 242#define gethosts(_family, _type) \
925c3c5c 243 { \
925c3c5c 244 struct hostent th; \
f04b1e1f 245 char *localcanon = NULL; \
925c3c5c 246 no_data = 0; \
f4a6be25
FW
247 while (1) \
248 { \
249 status = DL_CALL_FCT (fct, (name, _family, &th, \
250 tmpbuf->data, tmpbuf->length, \
251 &errno, &h_errno, NULL, &localcanon)); \
252 if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL \
253 || errno != ERANGE) \
254 break; \
255 if (!scratch_buffer_grow (tmpbuf)) \
256 { \
f4a6be25
FW
257 __resolv_context_put (res_ctx); \
258 result = -EAI_MEMORY; \
259 goto free_and_return; \
260 } \
261 } \
262 if (status == NSS_STATUS_NOTFOUND \
263 || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) \
925c3c5c 264 { \
53250a21 265 if (h_errno == NETDB_INTERNAL) \
925c3c5c 266 { \
352f4ff9 267 __resolv_context_put (res_ctx); \
7cbcdb36
SP
268 result = -EAI_SYSTEM; \
269 goto free_and_return; \
925c3c5c 270 } \
53250a21 271 if (h_errno == TRY_AGAIN) \
925c3c5c
UD
272 no_data = EAI_AGAIN; \
273 else \
53250a21 274 no_data = h_errno == NO_DATA; \
925c3c5c 275 } \
f4a6be25 276 else if (status == NSS_STATUS_SUCCESS) \
925c3c5c 277 { \
f4a6be25 278 if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, &addrmem)) \
925c3c5c 279 { \
352f4ff9 280 __resolv_context_put (res_ctx); \
4ab2ab03
FW
281 result = -EAI_SYSTEM; \
282 goto free_and_return; \
925c3c5c 283 } \
4ab2ab03 284 *pat = addrmem; \
28977c2c 285 \
6257fcfd
FW
286 if (localcanon != NULL && canon == NULL) \
287 { \
288 canonbuf = __strdup (localcanon); \
289 if (canonbuf == NULL) \
290 { \
8b222fa3 291 __resolv_context_put (res_ctx); \
6257fcfd
FW
292 result = -EAI_SYSTEM; \
293 goto free_and_return; \
294 } \
295 canon = canonbuf; \
296 } \
4ab2ab03 297 if (_family == AF_INET6 && *pat != NULL) \
28977c2c 298 got_ipv6 = true; \
925c3c5c 299 } \
218d76e0
UD
300 }
301
28977c2c 302
673cb072
FW
303/* This function is called if a canonical name is requested, but if
304 the service function did not provide it. It tries to obtain the
305 name using getcanonname_r from the same service NIP. If the name
306 cannot be canonicalized, return a copy of NAME. Return NULL on
307 memory allocation failure. The returned string is allocated on the
308 heap; the caller has to free it. */
309static char *
f4f3b091 310getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
673cb072 311{
499a92df 312 nss_getcanonname_r *cfct = __nss_lookup_function (nip, "getcanonname_r");
673cb072
FW
313 char *s = (char *) name;
314 if (cfct != NULL)
315 {
316 char buf[256];
673cb072 317 if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf),
53250a21 318 &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS)
673cb072
FW
319 /* If the canonical name cannot be determined, use the passed
320 string. */
321 s = (char *) name;
322 }
6257fcfd 323 return __strdup (name);
673cb072 324}
3af48b5b 325
40a55d20
UD
326static int
327gaih_inet (const char *name, const struct gaih_service *service,
01abbc0f 328 const struct addrinfo *req, struct addrinfo **pai,
cd065b68 329 unsigned int *naddrs, struct scratch_buffer *tmpbuf)
46ec036d 330{
3e2d61a3
UD
331 const struct gaih_typeproto *tp = gaih_inet_typeproto;
332 struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
1fb05e3d 333 struct gaih_addrtuple *at = NULL;
925c3c5c 334 bool got_ipv6 = false;
28977c2c 335 const char *canon = NULL;
b6c0f679 336 const char *orig_name = name;
cd065b68
FW
337
338 /* Reserve stack memory for the scratch buffer in the getaddrinfo
339 function. */
340 size_t alloca_used = sizeof (struct scratch_buffer);
46ec036d 341
40a55d20
UD
342 if (req->ai_protocol || req->ai_socktype)
343 {
f3ac48d0
UD
344 ++tp;
345
4b1fef84 346 while (tp->name[0]
3a47453d
UD
347 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
348 || (req->ai_protocol != 0
85599e53 349 && !(tp->protoflag & GAI_PROTO_PROTOANY)
3a47453d 350 && req->ai_protocol != tp->protocol)))
f3ac48d0
UD
351 ++tp;
352
4b1fef84 353 if (! tp->name[0])
6e4c40ba
UD
354 {
355 if (req->ai_socktype)
639a0ef8 356 return -EAI_SOCKTYPE;
6e4c40ba 357 else
639a0ef8 358 return -EAI_SERVICE;
6e4c40ba 359 }
40a55d20
UD
360 }
361
29546dd9 362 int port = 0;
40a55d20
UD
363 if (service != NULL)
364 {
f3ac48d0 365 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
639a0ef8 366 return -EAI_SERVICE;
f3ac48d0 367
40a55d20
UD
368 if (service->num < 0)
369 {
4b1fef84 370 if (tp->name[0])
40a55d20 371 {
238ae1eb 372 st = (struct gaih_servtuple *)
34a9094f 373 alloca_account (sizeof (struct gaih_servtuple), alloca_used);
238ae1eb 374
924b121c
FW
375 int rc = gaih_inet_serv (service->name, tp, req, st, tmpbuf);
376 if (__glibc_unlikely (rc != 0))
40a55d20
UD
377 return rc;
378 }
379 else
380 {
381 struct gaih_servtuple **pst = &st;
4b1fef84 382 for (tp++; tp->name[0]; tp++)
40a55d20 383 {
3a47453d
UD
384 struct gaih_servtuple *newp;
385
386 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
387 continue;
388
84a4fd33
UD
389 if (req->ai_socktype != 0
390 && req->ai_socktype != tp->socktype)
391 continue;
85599e53
UD
392 if (req->ai_protocol != 0
393 && !(tp->protoflag & GAI_PROTO_PROTOANY)
394 && req->ai_protocol != tp->protocol)
395 continue;
84a4fd33 396
3a47453d 397 newp = (struct gaih_servtuple *)
34a9094f
UD
398 alloca_account (sizeof (struct gaih_servtuple),
399 alloca_used);
238ae1eb 400
0df595b2
FW
401 if (gaih_inet_serv (service->name,
402 tp, req, newp, tmpbuf) != 0)
403 continue;
238ae1eb
UD
404
405 *pst = newp;
406 pst = &(newp->next);
40a55d20 407 }
3e2d61a3 408 if (st == (struct gaih_servtuple *) &nullserv)
639a0ef8 409 return -EAI_SERVICE;
40a55d20 410 }
46ec036d 411 }
40a55d20
UD
412 else
413 {
29546dd9
UD
414 port = htons (service->num);
415 goto got_port;
46ec036d 416 }
40a55d20 417 }
84a4fd33
UD
418 else
419 {
29546dd9
UD
420 got_port:
421
422 if (req->ai_socktype || req->ai_protocol)
423 {
34a9094f 424 st = alloca_account (sizeof (struct gaih_servtuple), alloca_used);
29546dd9
UD
425 st->next = NULL;
426 st->socktype = tp->socktype;
427 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
428 ? req->ai_protocol : tp->protocol);
429 st->port = port;
430 }
431 else
84a4fd33 432 {
29546dd9
UD
433 /* Neither socket type nor protocol is set. Return all socket types
434 we know about. */
435 struct gaih_servtuple **lastp = &st;
436 for (++tp; tp->name[0]; ++tp)
372bfcac
UD
437 if (tp->defaultflag)
438 {
439 struct gaih_servtuple *newp;
440
34a9094f
UD
441 newp = alloca_account (sizeof (struct gaih_servtuple),
442 alloca_used);
372bfcac
UD
443 newp->next = NULL;
444 newp->socktype = tp->socktype;
445 newp->protocol = tp->protocol;
446 newp->port = port;
447
448 *lastp = newp;
449 lastp = &newp->next;
450 }
84a4fd33
UD
451 }
452 }
40a55d20 453
34a9094f 454 bool malloc_name = false;
34a9094f 455 struct gaih_addrtuple *addrmem = NULL;
34a9094f 456 char *canonbuf = NULL;
34a9094f 457 int result = 0;
cd065b68 458
40a55d20
UD
459 if (name != NULL)
460 {
34a9094f 461 at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
a0bf6ac7 462 at->family = AF_UNSPEC;
c0bc5f7b 463 at->scopeid = 0;
40a55d20 464 at->next = NULL;
46ec036d 465
e2fd3cbe
UD
466 if (req->ai_flags & AI_IDN)
467 {
7f9f1ecb
FW
468 char *out;
469 result = __idna_to_dns_encoding (name, &out);
470 if (result != 0)
471 return -result;
472 name = out;
473 malloc_name = true;
e2fd3cbe 474 }
e2fd3cbe 475
108bc404 476 if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
a0bf6ac7
UD
477 {
478 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
479 at->family = AF_INET;
846d1362 480 else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
925c3c5c 481 {
28977c2c
UD
482 at->addr[3] = at->addr[0];
483 at->addr[2] = htonl (0xffff);
484 at->addr[1] = 0;
485 at->addr[0] = 0;
c1d98085 486 at->family = AF_INET6;
925c3c5c 487 }
a0bf6ac7 488 else
34a9094f
UD
489 {
490 result = -EAI_ADDRFAMILY;
491 goto free_and_return;
492 }
4376935c 493
4376935c 494 if (req->ai_flags & AI_CANONNAME)
5b353be3 495 canon = name;
a0bf6ac7 496 }
5b353be3 497 else if (at->family == AF_UNSPEC)
a0bf6ac7 498 {
abab6859 499 char *scope_delim = strchr (name, SCOPE_DELIMITER);
34a9094f 500 int e;
76b8266f
FW
501 if (scope_delim == NULL)
502 e = inet_pton (AF_INET6, name, at->addr);
503 else
504 e = __inet_pton_length (AF_INET6, name, scope_delim - name,
505 at->addr);
34a9094f 506 if (e > 0)
c0bc5f7b 507 {
c0bc5f7b
UD
508 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
509 at->family = AF_INET6;
87bb6b6c
UD
510 else if (req->ai_family == AF_INET
511 && IN6_IS_ADDR_V4MAPPED (at->addr))
512 {
28977c2c 513 at->addr[0] = at->addr[3];
87bb6b6c
UD
514 at->family = AF_INET;
515 }
c0bc5f7b 516 else
34a9094f
UD
517 {
518 result = -EAI_ADDRFAMILY;
519 goto free_and_return;
520 }
c0bc5f7b 521
80d8cb91
FW
522 if (scope_delim != NULL
523 && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
524 scope_delim + 1,
525 &at->scopeid) != 0)
c0bc5f7b 526 {
80d8cb91
FW
527 result = -EAI_NONAME;
528 goto free_and_return;
c0bc5f7b 529 }
4376935c 530
5b353be3
UD
531 if (req->ai_flags & AI_CANONNAME)
532 canon = name;
c0bc5f7b 533 }
a0bf6ac7 534 }
40a55d20 535
ce75c139 536 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
40a55d20 537 {
40a55d20 538 struct gaih_addrtuple **pat = &at;
a0bf6ac7 539 int no_data = 0;
218d76e0 540 int no_inet6_data = 0;
f4f3b091 541 nss_action_list nip;
28977c2c
UD
542 enum nss_status inet6_status = NSS_STATUS_UNAVAIL;
543 enum nss_status status = NSS_STATUS_UNAVAIL;
544 int no_more;
352f4ff9 545 struct resolv_context *res_ctx = NULL;
d19687d6 546
b957ced8
AS
547 /* If we do not have to look for IPv6 addresses or the canonical
548 name, use the simple, old functions, which do not support
549 IPv6 scope ids, nor retrieving the canonical name. */
550 if (req->ai_family == AF_INET
551 && (req->ai_flags & AI_CANONNAME) == 0)
d19687d6 552 {
d19687d6
UD
553 int rc;
554 struct hostent th;
555 struct hostent *h;
d19687d6 556
d19687d6
UD
557 while (1)
558 {
cd065b68
FW
559 rc = __gethostbyname2_r (name, AF_INET, &th,
560 tmpbuf->data, tmpbuf->length,
53250a21
FW
561 &h, &h_errno);
562 if (rc != ERANGE || h_errno != NETDB_INTERNAL)
d19687d6 563 break;
cd065b68 564 if (!scratch_buffer_grow (tmpbuf))
34a9094f 565 {
cd065b68
FW
566 result = -EAI_MEMORY;
567 goto free_and_return;
34a9094f 568 }
d19687d6
UD
569 }
570
571 if (rc == 0)
572 {
0b592a30 573 if (h != NULL)
34a9094f 574 {
4ab2ab03
FW
575 /* We found data, convert it. */
576 if (!convert_hostent_to_gaih_addrtuple
577 (req, AF_INET, h, &addrmem))
34a9094f 578 {
4ab2ab03
FW
579 result = -EAI_MEMORY;
580 goto free_and_return;
34a9094f 581 }
4ab2ab03 582 *pat = addrmem;
34a9094f 583 }
5f8340f5
FW
584 else
585 {
586 if (h_errno == NO_DATA)
587 result = -EAI_NODATA;
588 else
589 result = -EAI_NONAME;
590 goto free_and_return;
591 }
d19687d6
UD
592 }
593 else
594 {
53250a21
FW
595 if (h_errno == NETDB_INTERNAL)
596 result = -EAI_SYSTEM;
597 else if (h_errno == TRY_AGAIN)
34a9094f
UD
598 result = -EAI_AGAIN;
599 else
600 /* We made requests but they turned out no data.
601 The name is known, though. */
639a0ef8 602 result = -EAI_NODATA;
34a9094f
UD
603
604 goto free_and_return;
d19687d6
UD
605 }
606
607 goto process_list;
608 }
609
610#ifdef USE_NSCD
62417d7e
UD
611 if (__nss_not_use_nscd_hosts > 0
612 && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
613 __nss_not_use_nscd_hosts = 0;
d19687d6 614
c3e2f19b
UD
615 if (!__nss_not_use_nscd_hosts
616 && !__nss_database_custom[NSS_DBSIDX_hosts])
62417d7e
UD
617 {
618 /* Try to use nscd. */
619 struct nscd_ai_result *air = NULL;
53250a21 620 int err = __nscd_getai (name, &air, &h_errno);
62417d7e 621 if (air != NULL)
d19687d6 622 {
62417d7e
UD
623 /* Transform into gaih_addrtuple list. */
624 bool added_canon = (req->ai_flags & AI_CANONNAME) == 0;
625 char *addrs = air->addrs;
d19687d6 626
46ce8881
FW
627 addrmem = calloc (air->naddrs, sizeof (*addrmem));
628 if (addrmem == NULL)
34a9094f 629 {
46ce8881
FW
630 result = -EAI_MEMORY;
631 goto free_and_return;
34a9094f
UD
632 }
633
634 struct gaih_addrtuple *addrfree = addrmem;
62417d7e 635 for (int i = 0; i < air->naddrs; ++i)
d19687d6 636 {
8dc97517
AS
637 socklen_t size = (air->family[i] == AF_INET
638 ? INADDRSZ : IN6ADDRSZ);
639
a071766e
AS
640 if (!((air->family[i] == AF_INET
641 && req->ai_family == AF_INET6
642 && (req->ai_flags & AI_V4MAPPED) != 0)
643 || req->ai_family == AF_UNSPEC
644 || air->family[i] == req->ai_family))
8dc97517
AS
645 {
646 /* Skip over non-matching result. */
647 addrs += size;
648 continue;
649 }
a071766e 650
62417d7e
UD
651 if (*pat == NULL)
652 {
34a9094f 653 *pat = addrfree++;
62417d7e
UD
654 (*pat)->scopeid = 0;
655 }
656 uint32_t *pataddr = (*pat)->addr;
657 (*pat)->next = NULL;
658 if (added_canon || air->canon == NULL)
659 (*pat)->name = NULL;
34a9094f
UD
660 else if (canonbuf == NULL)
661 {
363911ce 662 canonbuf = __strdup (air->canon);
673cb072 663 if (canonbuf == NULL)
34a9094f 664 {
673cb072
FW
665 result = -EAI_MEMORY;
666 goto free_and_return;
34a9094f 667 }
673cb072 668 canon = (*pat)->name = canonbuf;
34a9094f 669 }
62417d7e
UD
670
671 if (air->family[i] == AF_INET
672 && req->ai_family == AF_INET6
673 && (req->ai_flags & AI_V4MAPPED))
674 {
675 (*pat)->family = AF_INET6;
676 pataddr[3] = *(uint32_t *) addrs;
677 pataddr[2] = htonl (0xffff);
678 pataddr[1] = 0;
679 pataddr[0] = 0;
680 pat = &((*pat)->next);
681 added_canon = true;
682 }
683 else if (req->ai_family == AF_UNSPEC
684 || air->family[i] == req->ai_family)
685 {
686 (*pat)->family = air->family[i];
687 memcpy (pataddr, addrs, size);
688 pat = &((*pat)->next);
689 added_canon = true;
690 if (air->family[i] == AF_INET6)
691 got_ipv6 = true;
692 }
693 addrs += size;
d19687d6 694 }
d19687d6 695
6535f55f
UD
696 free (air);
697
62417d7e 698 if (at->family == AF_UNSPEC)
34a9094f 699 {
639a0ef8 700 result = -EAI_NONAME;
34a9094f
UD
701 goto free_and_return;
702 }
d19687d6 703
62417d7e
UD
704 goto process_list;
705 }
66d90496
UD
706 else if (err == 0)
707 /* The database contains a negative entry. */
34a9094f 708 goto free_and_return;
66d90496 709 else if (__nss_not_use_nscd_hosts == 0)
62417d7e 710 {
53250a21 711 if (h_errno == NETDB_INTERNAL && errno == ENOMEM)
34a9094f 712 result = -EAI_MEMORY;
53250a21 713 else if (h_errno == TRY_AGAIN)
34a9094f
UD
714 result = -EAI_AGAIN;
715 else
716 result = -EAI_SYSTEM;
717
718 goto free_and_return;
62417d7e 719 }
d19687d6
UD
720 }
721#endif
28977c2c 722
9b456c5d 723 no_more = !__nss_database_get (nss_database_hosts, &nip);
28977c2c 724
9c42c64d
UD
725 /* If we are looking for both IPv4 and IPv6 address we don't
726 want the lookup functions to automatically promote IPv4
352f4ff9
FW
727 addresses to IPv6 addresses, so we use the no_inet6
728 function variant. */
729 res_ctx = __resolv_context_get ();
352f4ff9
FW
730 if (res_ctx == NULL)
731 no_more = 1;
40a55d20 732
28977c2c
UD
733 while (!no_more)
734 {
c3dfadb8 735 no_data = 0;
499a92df 736 nss_gethostbyname4_r *fct4 = NULL;
8479f23a
JL
737
738 /* gethostbyname4_r sends out parallel A and AAAA queries and
739 is thus only suitable for PF_UNSPEC. */
740 if (req->ai_family == PF_UNSPEC)
741 fct4 = __nss_lookup_function (nip, "gethostbyname4_r");
742
1eb946b9 743 if (fct4 != NULL)
218d76e0 744 {
1eb946b9 745 while (1)
64ab2317 746 {
cd065b68
FW
747 status = DL_CALL_FCT (fct4, (name, pat,
748 tmpbuf->data, tmpbuf->length,
53250a21 749 &errno, &h_errno,
1eb946b9 750 NULL));
bfbbc63f
UD
751 if (status == NSS_STATUS_SUCCESS)
752 break;
1eb946b9 753 if (status != NSS_STATUS_TRYAGAIN
53250a21 754 || errno != ERANGE || h_errno != NETDB_INTERNAL)
1eb946b9 755 {
53250a21 756 if (h_errno == TRY_AGAIN)
1eb946b9
UD
757 no_data = EAI_AGAIN;
758 else
53250a21 759 no_data = h_errno == NO_DATA;
1eb946b9
UD
760 break;
761 }
34a9094f 762
cd065b68 763 if (!scratch_buffer_grow (tmpbuf))
34a9094f 764 {
352f4ff9 765 __resolv_context_put (res_ctx);
cd065b68
FW
766 result = -EAI_MEMORY;
767 goto free_and_return;
34a9094f 768 }
64ab2317 769 }
1eb946b9
UD
770
771 if (status == NSS_STATUS_SUCCESS)
28977c2c 772 {
c0244a9d
UD
773 assert (!no_data);
774 no_data = 1;
775
91c8a74b
UD
776 if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
777 canon = (*pat)->name;
218d76e0 778
1eb946b9 779 while (*pat != NULL)
c0244a9d
UD
780 {
781 if ((*pat)->family == AF_INET
782 && req->ai_family == AF_INET6
783 && (req->ai_flags & AI_V4MAPPED) != 0)
784 {
785 uint32_t *pataddr = (*pat)->addr;
786 (*pat)->family = AF_INET6;
787 pataddr[3] = pataddr[0];
788 pataddr[2] = htonl (0xffff);
789 pataddr[1] = 0;
790 pataddr[0] = 0;
791 pat = &((*pat)->next);
792 no_data = 0;
793 }
e12df166 794 else if (req->ai_family == AF_UNSPEC
c0244a9d
UD
795 || (*pat)->family == req->ai_family)
796 {
797 pat = &((*pat)->next);
798
799 no_data = 0;
800 if (req->ai_family == AF_INET6)
801 got_ipv6 = true;
802 }
803 else
804 *pat = ((*pat)->next);
805 }
1eb946b9 806 }
c0244a9d
UD
807
808 no_inet6_data = no_data;
1eb946b9
UD
809 }
810 else
811 {
499a92df 812 nss_gethostbyname3_r *fct = NULL;
1eb946b9
UD
813 if (req->ai_flags & AI_CANONNAME)
814 /* No need to use this function if we do not look for
815 the canonical name. The function does not exist in
816 all NSS modules and therefore the lookup would
817 often fail. */
818 fct = __nss_lookup_function (nip, "gethostbyname3_r");
819 if (fct == NULL)
820 /* We are cheating here. The gethostbyname2_r
821 function does not have the same interface as
822 gethostbyname3_r but the extra arguments the
823 latter takes are added at the end. So the
824 gethostbyname2_r code will just ignore them. */
825 fct = __nss_lookup_function (nip, "gethostbyname2_r");
826
827 if (fct != NULL)
828 {
829 if (req->ai_family == AF_INET6
830 || req->ai_family == AF_UNSPEC)
28977c2c 831 {
1eb946b9 832 gethosts (AF_INET6, struct in6_addr);
28977c2c
UD
833 no_inet6_data = no_data;
834 inet6_status = status;
835 }
1eb946b9
UD
836 if (req->ai_family == AF_INET
837 || req->ai_family == AF_UNSPEC
838 || (req->ai_family == AF_INET6
839 && (req->ai_flags & AI_V4MAPPED)
840 /* Avoid generating the mapped addresses if we
841 know we are not going to need them. */
842 && ((req->ai_flags & AI_ALL) || !got_ipv6)))
28977c2c 843 {
1eb946b9 844 gethosts (AF_INET, struct in_addr);
afd7b703 845
1eb946b9 846 if (req->ai_family == AF_INET)
afd7b703 847 {
1eb946b9
UD
848 no_inet6_data = no_data;
849 inet6_status = status;
afd7b703 850 }
28977c2c
UD
851 }
852
1eb946b9
UD
853 /* If we found one address for AF_INET or AF_INET6,
854 don't continue the search. */
855 if (inet6_status == NSS_STATUS_SUCCESS
856 || status == NSS_STATUS_SUCCESS)
857 {
858 if ((req->ai_flags & AI_CANONNAME) != 0
859 && canon == NULL)
860 {
673cb072
FW
861 canonbuf = getcanonname (nip, at, name);
862 if (canonbuf == NULL)
1eb946b9 863 {
352f4ff9 864 __resolv_context_put (res_ctx);
673cb072
FW
865 result = -EAI_MEMORY;
866 goto free_and_return;
1eb946b9 867 }
673cb072 868 canon = canonbuf;
1eb946b9 869 }
07f9ca32 870 status = NSS_STATUS_SUCCESS;
1eb946b9 871 }
7c930290
UD
872 else
873 {
874 /* We can have different states for AF_INET and
875 AF_INET6. Try to find a useful one for both. */
876 if (inet6_status == NSS_STATUS_TRYAGAIN)
877 status = NSS_STATUS_TRYAGAIN;
878 else if (status == NSS_STATUS_UNAVAIL
879 && inet6_status != NSS_STATUS_UNAVAIL)
880 status = inet6_status;
881 }
1eb946b9 882 }
65731753 883 else
3d04f5db 884 {
ad816a5e
FW
885 /* Could not locate any of the lookup functions.
886 The NSS lookup code does not consistently set
887 errno, so we need to supply our own error
888 code here. The root cause could either be a
889 resource allocation failure, or a missing
890 service function in the DSO (so it should not
891 be listed in /etc/nsswitch.conf). Assume the
892 former, and return EBUSY. */
3d04f5db 893 status = NSS_STATUS_UNAVAIL;
ad816a5e
FW
894 __set_h_errno (NETDB_INTERNAL);
895 __set_errno (EBUSY);
3d04f5db 896 }
218d76e0
UD
897 }
898
28977c2c
UD
899 if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
900 break;
901
f4f3b091
DD
902 nip++;
903 if (nip->module == NULL)
28977c2c 904 no_more = -1;
2ce1a10f 905 }
a0bf6ac7 906
352f4ff9 907 __resolv_context_put (res_ctx);
28977c2c 908
a2881ef0
FW
909 /* If we have a failure which sets errno, report it using
910 EAI_SYSTEM. */
911 if ((status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL)
912 && h_errno == NETDB_INTERNAL)
cfde9b46 913 {
639a0ef8 914 result = -EAI_SYSTEM;
cfde9b46
SP
915 goto free_and_return;
916 }
917
5ad81f40 918 if (no_data != 0 && no_inet6_data != 0)
7813b61a
UD
919 {
920 /* If both requests timed out report this. */
921 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
34a9094f
UD
922 result = -EAI_AGAIN;
923 else
924 /* We made requests but they turned out no data. The name
925 is known, though. */
639a0ef8 926 result = -EAI_NODATA;
7813b61a 927
34a9094f 928 goto free_and_return;
7813b61a 929 }
46ec036d 930 }
40a55d20 931
d19687d6 932 process_list:
40a55d20 933 if (at->family == AF_UNSPEC)
34a9094f 934 {
639a0ef8 935 result = -EAI_NONAME;
34a9094f
UD
936 goto free_and_return;
937 }
46ec036d 938 }
40a55d20
UD
939 else
940 {
7396d844 941 struct gaih_addrtuple *atr;
34a9094f 942 atr = at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
a0bf6ac7 943 memset (at, '\0', sizeof (struct gaih_addrtuple));
40a55d20 944
28977c2c 945 if (req->ai_family == AF_UNSPEC)
7396d844 946 {
a0bf6ac7
UD
947 at->next = __alloca (sizeof (struct gaih_addrtuple));
948 memset (at->next, '\0', sizeof (struct gaih_addrtuple));
7396d844 949 }
40a55d20 950
28977c2c 951 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
7396d844
UD
952 {
953 at->family = AF_INET6;
954 if ((req->ai_flags & AI_PASSIVE) == 0)
a585ba22 955 memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
7396d844
UD
956 atr = at->next;
957 }
40a55d20 958
28977c2c 959 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
7396d844
UD
960 {
961 atr->family = AF_INET;
962 if ((req->ai_flags & AI_PASSIVE) == 0)
28977c2c 963 atr->addr[0] = htonl (INADDR_LOOPBACK);
7396d844 964 }
46ec036d 965 }
1fb05e3d 966
46ec036d 967 {
46ec036d
UD
968 struct gaih_servtuple *st2;
969 struct gaih_addrtuple *at2 = at;
28977c2c 970 size_t socklen;
85599e53 971 sa_family_t family;
40a55d20 972
f21acc89
UD
973 /*
974 buffer is the size of an unformatted IPv6 address in printable format.
975 */
40a55d20
UD
976 while (at2 != NULL)
977 {
163288fe
UD
978 /* Only the first entry gets the canonical name. */
979 if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
40a55d20 980 {
28977c2c 981 if (canon == NULL)
b957ced8
AS
982 /* If the canonical name cannot be determined, use
983 the passed in string. */
984 canon = orig_name;
40a55d20 985
7f9f1ecb
FW
986 bool do_idn = req->ai_flags & AI_CANONIDN;
987 if (do_idn)
de079fee
UD
988 {
989 char *out;
7f9f1ecb
FW
990 int rc = __idna_from_dns_encoding (canon, &out);
991 if (rc == 0)
992 canon = out;
993 else if (rc == EAI_IDN_ENCODE)
994 /* Use the punycode name as a fallback. */
995 do_idn = false;
996 else
de079fee 997 {
7f9f1ecb 998 result = -rc;
34a9094f 999 goto free_and_return;
de079fee 1000 }
de079fee 1001 }
7f9f1ecb 1002 if (!do_idn)
b9343764 1003 {
673cb072
FW
1004 if (canonbuf != NULL)
1005 /* We already allocated the string using malloc, but
1006 the buffer is now owned by canon. */
1007 canonbuf = NULL;
34a9094f
UD
1008 else
1009 {
ae65d4f3 1010 canon = __strdup (canon);
34a9094f
UD
1011 if (canon == NULL)
1012 {
34a9094f
UD
1013 result = -EAI_MEMORY;
1014 goto free_and_return;
1015 }
1016 }
b9343764 1017 }
40a55d20 1018 }
40a55d20 1019
abab6859
UD
1020 family = at2->family;
1021 if (family == AF_INET6)
85599e53 1022 {
85599e53 1023 socklen = sizeof (struct sockaddr_in6);
925c3c5c
UD
1024
1025 /* If we looked up IPv4 mapped address discard them here if
1026 the caller isn't interested in all address and we have
1027 found at least one IPv6 address. */
28977c2c 1028 if (got_ipv6
925c3c5c
UD
1029 && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
1030 && IN6_IS_ADDR_V4MAPPED (at2->addr))
1031 goto ignore;
85599e53 1032 }
40a55d20 1033 else
abab6859 1034 socklen = sizeof (struct sockaddr_in);
40a55d20
UD
1035
1036 for (st2 = st; st2 != NULL; st2 = st2->next)
1037 {
a24c5ac4
UD
1038 struct addrinfo *ai;
1039 ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
1040 if (ai == NULL)
e7c8359e
UD
1041 {
1042 free ((char *) canon);
34a9094f
UD
1043 result = -EAI_MEMORY;
1044 goto free_and_return;
e7c8359e 1045 }
40a55d20 1046
a24c5ac4
UD
1047 ai->ai_flags = req->ai_flags;
1048 ai->ai_family = family;
1049 ai->ai_socktype = st2->socktype;
1050 ai->ai_protocol = st2->protocol;
1051 ai->ai_addrlen = socklen;
1052 ai->ai_addr = (void *) (ai + 1);
b9343764
UD
1053
1054 /* We only add the canonical name once. */
a24c5ac4 1055 ai->ai_canonname = (char *) canon;
b9343764
UD
1056 canon = NULL;
1057
beb32642 1058#ifdef _HAVE_SA_LEN
a24c5ac4 1059 ai->ai_addr->sa_len = socklen;
beb32642 1060#endif /* _HAVE_SA_LEN */
a24c5ac4 1061 ai->ai_addr->sa_family = family;
5a97622d 1062
e7c8359e
UD
1063 /* In case of an allocation error the list must be NULL
1064 terminated. */
1065 ai->ai_next = NULL;
1066
85599e53 1067 if (family == AF_INET6)
40a55d20
UD
1068 {
1069 struct sockaddr_in6 *sin6p =
a24c5ac4 1070 (struct sockaddr_in6 *) ai->ai_addr;
46ec036d 1071
28977c2c 1072 sin6p->sin6_port = st2->port;
40a55d20
UD
1073 sin6p->sin6_flowinfo = 0;
1074 memcpy (&sin6p->sin6_addr,
1075 at2->addr, sizeof (struct in6_addr));
c0bc5f7b 1076 sin6p->sin6_scope_id = at2->scopeid;
40a55d20
UD
1077 }
1078 else
1079 {
1080 struct sockaddr_in *sinp =
a24c5ac4 1081 (struct sockaddr_in *) ai->ai_addr;
28977c2c 1082 sinp->sin_port = st2->port;
40a55d20
UD
1083 memcpy (&sinp->sin_addr,
1084 at2->addr, sizeof (struct in_addr));
1085 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
1086 }
46ec036d 1087
a24c5ac4 1088 pai = &(ai->ai_next);
40a55d20 1089 }
46ec036d 1090
01abbc0f
UD
1091 ++*naddrs;
1092
925c3c5c 1093 ignore:
40a55d20
UD
1094 at2 = at2->next;
1095 }
46ec036d 1096 }
34a9094f
UD
1097
1098 free_and_return:
1099 if (malloc_name)
1100 free ((char *) name);
46ce8881 1101 free (addrmem);
673cb072 1102 free (canonbuf);
34a9094f
UD
1103
1104 return result;
46ec036d
UD
1105}
1106
46ec036d 1107
5ddb5bf5
UD
1108struct sort_result
1109{
1110 struct addrinfo *dest_addr;
0efd1956
UD
1111 /* Using sockaddr_storage is for now overkill. We only support IPv4
1112 and IPv6 so far. If this changes at some point we can adjust the
1113 type here. */
1114 struct sockaddr_in6 source_addr;
d19687d6 1115 uint8_t source_addr_len;
5ddb5bf5 1116 bool got_source_addr;
3af48b5b 1117 uint8_t source_addr_flags;
6f3914d5 1118 uint8_t prefixlen;
773e79b3
UD
1119 uint32_t index;
1120 int32_t native;
1121};
1122
1123struct sort_result_combo
1124{
1125 struct sort_result *results;
1126 int nresults;
5ddb5bf5
UD
1127};
1128
1129
ee72b971
UD
1130#if __BYTE_ORDER == __BIG_ENDIAN
1131# define htonl_c(n) n
1132#else
1133# define htonl_c(n) __bswap_constant_32 (n)
1134#endif
1135
1136static const struct scopeentry
1137{
1138 union
1139 {
1140 char addr[4];
1141 uint32_t addr32;
1142 };
1143 uint32_t netmask;
1144 int32_t scope;
1145} default_scopes[] =
1146 {
1147 /* Link-local addresses: scope 2. */
1148 { { { 169, 254, 0, 0 } }, htonl_c (0xffff0000), 2 },
1149 { { { 127, 0, 0, 0 } }, htonl_c (0xff000000), 2 },
ee72b971
UD
1150 /* Default: scope 14. */
1151 { { { 0, 0, 0, 0 } }, htonl_c (0x00000000), 14 }
1152 };
1153
1154/* The label table. */
1155static const struct scopeentry *scopes;
1156
1157
5ddb5bf5 1158static int
0efd1956 1159get_scope (const struct sockaddr_in6 *in6)
5ddb5bf5
UD
1160{
1161 int scope;
0efd1956 1162 if (in6->sin6_family == PF_INET6)
5ddb5bf5 1163 {
5ddb5bf5
UD
1164 if (! IN6_IS_ADDR_MULTICAST (&in6->sin6_addr))
1165 {
5fab5544
UD
1166 if (IN6_IS_ADDR_LINKLOCAL (&in6->sin6_addr)
1167 /* RFC 4291 2.5.3 says that the loopback address is to be
1168 treated like a link-local address. */
1169 || IN6_IS_ADDR_LOOPBACK (&in6->sin6_addr))
5ddb5bf5
UD
1170 scope = 2;
1171 else if (IN6_IS_ADDR_SITELOCAL (&in6->sin6_addr))
1172 scope = 5;
1173 else
1174 /* XXX Is this the correct default behavior? */
1175 scope = 14;
1176 }
1177 else
1178 scope = in6->sin6_addr.s6_addr[1] & 0xf;
1179 }
0efd1956 1180 else if (in6->sin6_family == PF_INET)
5ddb5bf5 1181 {
0efd1956 1182 const struct sockaddr_in *in = (const struct sockaddr_in *) in6;
ee72b971
UD
1183
1184 size_t cnt = 0;
1185 while (1)
1186 {
1187 if ((in->sin_addr.s_addr & scopes[cnt].netmask)
1188 == scopes[cnt].addr32)
1189 return scopes[cnt].scope;
1190
1191 ++cnt;
1192 }
1193 /* NOTREACHED */
5ddb5bf5
UD
1194 }
1195 else
1196 /* XXX What is a good default? */
1197 scope = 15;
1198
1199 return scope;
1200}
1201
1202
77dd4c3b 1203struct prefixentry
5ddb5bf5
UD
1204{
1205 struct in6_addr prefix;
1206 unsigned int bits;
1207 int val;
77dd4c3b
UD
1208};
1209
1210
1211/* The label table. */
1212static const struct prefixentry *labels;
1213
1214/* Default labels. */
1215static const struct prefixentry default_labels[] =
5ddb5bf5
UD
1216 {
1217 /* See RFC 3484 for the details. */
6107639e
UD
1218 { { .__in6_u
1219 = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } }
1221 }, 128, 0 },
1222 { { .__in6_u
1223 = { .__u6_addr8 = { 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
1225 }, 16, 2 },
1226 { { .__in6_u
1227 = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
1229 }, 96, 3 },
1230 { { .__in6_u
1231 = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1232 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } }
1233 }, 96, 4 },
6e2a7825
UD
1234 /* The next two entries differ from RFC 3484. We need to treat
1235 IPv6 site-local addresses special because they are never NATed,
1236 unlike site-locale IPv4 addresses. If this would not happen, on
1237 machines which have only IPv4 and IPv6 site-local addresses, the
1238 sorting would prefer the IPv6 site-local addresses, causing
1239 unnecessary delays when trying to connect to a global IPv6 address
1240 through a site-local IPv6 address. */
6107639e
UD
1241 { { .__in6_u
1242 = { .__u6_addr8 = { 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1243 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
1244 }, 10, 5 },
1245 { { .__in6_u
1246 = { .__u6_addr8 = { 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
1248 }, 7, 6 },
f4a79765 1249 /* Additional rule for Teredo tunnels. */
6107639e
UD
1250 { { .__in6_u
1251 = { .__u6_addr8 = { 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
1253 }, 32, 7 },
1254 { { .__in6_u
1255 = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
1257 }, 0, 1 }
5ddb5bf5
UD
1258 };
1259
1260
77dd4c3b
UD
1261/* The precedence table. */
1262static const struct prefixentry *precedence;
1263
1264/* The default precedences. */
1265static const struct prefixentry default_precedence[] =
5ddb5bf5
UD
1266 {
1267 /* See RFC 3484 for the details. */
6107639e
UD
1268 { { .__in6_u
1269 = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1270 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } }
1271 }, 128, 50 },
1272 { { .__in6_u
1273 = { .__u6_addr8 = { 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1274 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
1275 }, 16, 30 },
1276 { { .__in6_u
1277 = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
1279 }, 96, 20 },
1280 { { .__in6_u
1281 = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1282 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } }
1283 }, 96, 10 },
1284 { { .__in6_u
1285 = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
1287 }, 0, 40 }
5ddb5bf5
UD
1288 };
1289
1290
1291static int
0efd1956 1292match_prefix (const struct sockaddr_in6 *in6,
77dd4c3b 1293 const struct prefixentry *list, int default_val)
5ddb5bf5
UD
1294{
1295 int idx;
1296 struct sockaddr_in6 in6_mem;
5ddb5bf5 1297
0efd1956 1298 if (in6->sin6_family == PF_INET)
5ddb5bf5 1299 {
0efd1956 1300 const struct sockaddr_in *in = (const struct sockaddr_in *) in6;
5ddb5bf5 1301
5846c4e2 1302 /* Construct a V4-to-6 mapped address. */
5ddb5bf5
UD
1303 in6_mem.sin6_family = PF_INET6;
1304 in6_mem.sin6_port = in->sin_port;
1305 in6_mem.sin6_flowinfo = 0;
5846c4e2
UD
1306 memset (&in6_mem.sin6_addr, '\0', sizeof (in6_mem.sin6_addr));
1307 in6_mem.sin6_addr.s6_addr16[5] = 0xffff;
1308 in6_mem.sin6_addr.s6_addr32[3] = in->sin_addr.s_addr;
1309 in6_mem.sin6_scope_id = 0;
5ddb5bf5
UD
1310
1311 in6 = &in6_mem;
1312 }
0efd1956 1313 else if (in6->sin6_family != PF_INET6)
5ddb5bf5
UD
1314 return default_val;
1315
1316 for (idx = 0; ; ++idx)
1317 {
1318 unsigned int bits = list[idx].bits;
d4ed7561
UD
1319 const uint8_t *mask = list[idx].prefix.s6_addr;
1320 const uint8_t *val = in6->sin6_addr.s6_addr;
5ddb5bf5 1321
207cce4c 1322 while (bits >= 8)
5ddb5bf5
UD
1323 {
1324 if (*mask != *val)
1325 break;
1326
1327 ++mask;
1328 ++val;
1329 bits -= 8;
1330 }
1331
1332 if (bits < 8)
1333 {
d9a3ae7f 1334 if ((*mask & (0xff00 >> bits)) == (*val & (0xff00 >> bits)))
5ddb5bf5
UD
1335 /* Match! */
1336 break;
1337 }
1338 }
1339
1340 return list[idx].val;
1341}
1342
1343
1344static int
0efd1956 1345get_label (const struct sockaddr_in6 *in6)
5ddb5bf5
UD
1346{
1347 /* XXX What is a good default value? */
0efd1956 1348 return match_prefix (in6, labels, INT_MAX);
5ddb5bf5
UD
1349}
1350
1351
1352static int
0efd1956 1353get_precedence (const struct sockaddr_in6 *in6)
5ddb5bf5
UD
1354{
1355 /* XXX What is a good default value? */
0efd1956 1356 return match_prefix (in6, precedence, 0);
5ddb5bf5
UD
1357}
1358
1359
c6bad06a
UD
1360/* Find last bit set in a word. */
1361static int
1362fls (uint32_t a)
1363{
1364 uint32_t mask;
6f3914d5 1365 int n;
c6bad06a
UD
1366 for (n = 0, mask = 1 << 31; n < 32; mask >>= 1, ++n)
1367 if ((a & mask) != 0)
1368 break;
1369 return n;
1370}
1371
1372
5ddb5bf5 1373static int
773e79b3 1374rfc3484_sort (const void *p1, const void *p2, void *arg)
5ddb5bf5 1375{
0efd1956
UD
1376 const size_t idx1 = *(const size_t *) p1;
1377 const size_t idx2 = *(const size_t *) p2;
773e79b3 1378 struct sort_result_combo *src = (struct sort_result_combo *) arg;
0efd1956
UD
1379 struct sort_result *a1 = &src->results[idx1];
1380 struct sort_result *a2 = &src->results[idx2];
5ddb5bf5
UD
1381
1382 /* Rule 1: Avoid unusable destinations.
1383 We have the got_source_addr flag set if the destination is reachable. */
1384 if (a1->got_source_addr && ! a2->got_source_addr)
1385 return -1;
1386 if (! a1->got_source_addr && a2->got_source_addr)
1387 return 1;
1388
1389
1390 /* Rule 2: Prefer matching scope. Only interesting if both
1391 destination addresses are IPv6. */
1392 int a1_dst_scope
0efd1956 1393 = get_scope ((struct sockaddr_in6 *) a1->dest_addr->ai_addr);
5ddb5bf5
UD
1394
1395 int a2_dst_scope
0efd1956 1396 = get_scope ((struct sockaddr_in6 *) a2->dest_addr->ai_addr);
5ddb5bf5
UD
1397
1398 if (a1->got_source_addr)
1399 {
1400 int a1_src_scope = get_scope (&a1->source_addr);
1401 int a2_src_scope = get_scope (&a2->source_addr);
1402
1403 if (a1_dst_scope == a1_src_scope && a2_dst_scope != a2_src_scope)
1404 return -1;
1405 if (a1_dst_scope != a1_src_scope && a2_dst_scope == a2_src_scope)
1406 return 1;
1407 }
1408
1409
3af48b5b
UD
1410 /* Rule 3: Avoid deprecated addresses. */
1411 if (a1->got_source_addr)
1412 {
1413 if (!(a1->source_addr_flags & in6ai_deprecated)
1414 && (a2->source_addr_flags & in6ai_deprecated))
1415 return -1;
1416 if ((a1->source_addr_flags & in6ai_deprecated)
1417 && !(a2->source_addr_flags & in6ai_deprecated))
1418 return 1;
1419 }
5ddb5bf5 1420
457b559e
UD
1421 /* Rule 4: Prefer home addresses. */
1422 if (a1->got_source_addr)
1423 {
1424 if (!(a1->source_addr_flags & in6ai_homeaddress)
1425 && (a2->source_addr_flags & in6ai_homeaddress))
4a85a8ee 1426 return 1;
457b559e
UD
1427 if ((a1->source_addr_flags & in6ai_homeaddress)
1428 && !(a2->source_addr_flags & in6ai_homeaddress))
4a85a8ee 1429 return -1;
457b559e 1430 }
5ddb5bf5
UD
1431
1432 /* Rule 5: Prefer matching label. */
1433 if (a1->got_source_addr)
1434 {
1435 int a1_dst_label
0efd1956 1436 = get_label ((struct sockaddr_in6 *) a1->dest_addr->ai_addr);
5ddb5bf5
UD
1437 int a1_src_label = get_label (&a1->source_addr);
1438
1439 int a2_dst_label
0efd1956 1440 = get_label ((struct sockaddr_in6 *) a2->dest_addr->ai_addr);
5ddb5bf5
UD
1441 int a2_src_label = get_label (&a2->source_addr);
1442
1443 if (a1_dst_label == a1_src_label && a2_dst_label != a2_src_label)
1444 return -1;
1445 if (a1_dst_label != a1_src_label && a2_dst_label == a2_src_label)
1446 return 1;
1447 }
1448
1449
1450 /* Rule 6: Prefer higher precedence. */
1451 int a1_prec
0efd1956 1452 = get_precedence ((struct sockaddr_in6 *) a1->dest_addr->ai_addr);
5ddb5bf5 1453 int a2_prec
0efd1956 1454 = get_precedence ((struct sockaddr_in6 *) a2->dest_addr->ai_addr);
5ddb5bf5
UD
1455
1456 if (a1_prec > a2_prec)
1457 return -1;
1458 if (a1_prec < a2_prec)
1459 return 1;
1460
1461
3af48b5b
UD
1462 /* Rule 7: Prefer native transport. */
1463 if (a1->got_source_addr)
1464 {
773e79b3
UD
1465 /* The same interface index means the same interface which means
1466 there is no difference in transport. This should catch many
1467 (most?) cases. */
1468 if (a1->index != a2->index)
1469 {
49029a66
UD
1470 int a1_native = a1->native;
1471 int a2_native = a2->native;
1472
1473 if (a1_native == -1 || a2_native == -1)
773e79b3 1474 {
49029a66
UD
1475 uint32_t a1_index;
1476 if (a1_native == -1)
1477 {
1478 /* If we do not have the information use 'native' as
1479 the default. */
1480 a1_native = 0;
1481 a1_index = a1->index;
1482 }
1483 else
1484 a1_index = 0xffffffffu;
1485
1486 uint32_t a2_index;
1487 if (a2_native == -1)
1488 {
1489 /* If we do not have the information use 'native' as
1490 the default. */
1491 a2_native = 0;
1492 a2_index = a2->index;
1493 }
1494 else
1495 a2_index = 0xffffffffu;
1496
1497 __check_native (a1_index, &a1_native, a2_index, &a2_native);
773e79b3
UD
1498
1499 /* Fill in the results in all the records. */
1500 for (int i = 0; i < src->nresults; ++i)
894f3f10 1501 if (a1_index != -1 && src->results[i].index == a1_index)
49029a66
UD
1502 {
1503 assert (src->results[i].native == -1
1504 || src->results[i].native == a1_native);
773e79b3 1505 src->results[i].native = a1_native;
49029a66 1506 }
894f3f10 1507 else if (a2_index != -1 && src->results[i].index == a2_index)
49029a66
UD
1508 {
1509 assert (src->results[i].native == -1
1510 || src->results[i].native == a2_native);
773e79b3 1511 src->results[i].native = a2_native;
49029a66 1512 }
773e79b3 1513 }
3af48b5b 1514
49029a66 1515 if (a1_native && !a2_native)
773e79b3 1516 return -1;
49029a66 1517 if (!a1_native && a2_native)
773e79b3
UD
1518 return 1;
1519 }
3af48b5b 1520 }
5ddb5bf5
UD
1521
1522
1523 /* Rule 8: Prefer smaller scope. */
1524 if (a1_dst_scope < a2_dst_scope)
1525 return -1;
1526 if (a1_dst_scope > a2_dst_scope)
1527 return 1;
1528
1529
1530 /* Rule 9: Use longest matching prefix. */
1531 if (a1->got_source_addr
1532 && a1->dest_addr->ai_family == a2->dest_addr->ai_family)
1533 {
1534 int bit1 = 0;
1535 int bit2 = 0;
1536
1537 if (a1->dest_addr->ai_family == PF_INET)
1538 {
0efd1956
UD
1539 assert (a1->source_addr.sin6_family == PF_INET);
1540 assert (a2->source_addr.sin6_family == PF_INET);
5ddb5bf5 1541
6f3914d5
UD
1542 /* Outside of subnets, as defined by the network masks,
1543 common address prefixes for IPv4 addresses make no sense.
1544 So, define a non-zero value only if source and
1545 destination address are on the same subnet. */
1546 struct sockaddr_in *in1_dst
1547 = (struct sockaddr_in *) a1->dest_addr->ai_addr;
1548 in_addr_t in1_dst_addr = ntohl (in1_dst->sin_addr.s_addr);
1549 struct sockaddr_in *in1_src
1550 = (struct sockaddr_in *) &a1->source_addr;
1551 in_addr_t in1_src_addr = ntohl (in1_src->sin_addr.s_addr);
1552 in_addr_t netmask1 = 0xffffffffu << (32 - a1->prefixlen);
1553
1554 if ((in1_src_addr & netmask1) == (in1_dst_addr & netmask1))
1555 bit1 = fls (in1_dst_addr ^ in1_src_addr);
1556
1557 struct sockaddr_in *in2_dst
1558 = (struct sockaddr_in *) a2->dest_addr->ai_addr;
1559 in_addr_t in2_dst_addr = ntohl (in2_dst->sin_addr.s_addr);
1560 struct sockaddr_in *in2_src
1561 = (struct sockaddr_in *) &a2->source_addr;
1562 in_addr_t in2_src_addr = ntohl (in2_src->sin_addr.s_addr);
1563 in_addr_t netmask2 = 0xffffffffu << (32 - a2->prefixlen);
1564
1565 if ((in2_src_addr & netmask2) == (in2_dst_addr & netmask2))
1566 bit2 = fls (in2_dst_addr ^ in2_src_addr);
5ddb5bf5
UD
1567 }
1568 else if (a1->dest_addr->ai_family == PF_INET6)
1569 {
0efd1956
UD
1570 assert (a1->source_addr.sin6_family == PF_INET6);
1571 assert (a2->source_addr.sin6_family == PF_INET6);
5ddb5bf5
UD
1572
1573 struct sockaddr_in6 *in1_dst;
1574 struct sockaddr_in6 *in1_src;
1575 struct sockaddr_in6 *in2_dst;
1576 struct sockaddr_in6 *in2_src;
1577
1578 in1_dst = (struct sockaddr_in6 *) a1->dest_addr->ai_addr;
1579 in1_src = (struct sockaddr_in6 *) &a1->source_addr;
1580 in2_dst = (struct sockaddr_in6 *) a2->dest_addr->ai_addr;
1581 in2_src = (struct sockaddr_in6 *) &a2->source_addr;
1582
1583 int i;
1584 for (i = 0; i < 4; ++i)
1585 if (in1_dst->sin6_addr.s6_addr32[i]
1586 != in1_src->sin6_addr.s6_addr32[i]
1587 || (in2_dst->sin6_addr.s6_addr32[i]
1588 != in2_src->sin6_addr.s6_addr32[i]))
1589 break;
1590
1591 if (i < 4)
1592 {
c6bad06a
UD
1593 bit1 = fls (ntohl (in1_dst->sin6_addr.s6_addr32[i]
1594 ^ in1_src->sin6_addr.s6_addr32[i]));
1595 bit2 = fls (ntohl (in2_dst->sin6_addr.s6_addr32[i]
1596 ^ in2_src->sin6_addr.s6_addr32[i]));
5ddb5bf5
UD
1597 }
1598 }
1599
1600 if (bit1 > bit2)
1601 return -1;
1602 if (bit1 < bit2)
1603 return 1;
1604 }
1605
1606
6f55ed88
UD
1607 /* Rule 10: Otherwise, leave the order unchanged. To ensure this
1608 compare with the value indicating the order in which the entries
1609 have been received from the services. NB: no two entries can have
1610 the same order so the test will never return zero. */
0efd1956 1611 return idx1 < idx2 ? -1 : 1;
5ddb5bf5
UD
1612}
1613
1614
3af48b5b
UD
1615static int
1616in6aicmp (const void *p1, const void *p2)
1617{
1618 struct in6addrinfo *a1 = (struct in6addrinfo *) p1;
1619 struct in6addrinfo *a2 = (struct in6addrinfo *) p2;
1620
1621 return memcmp (a1->addr, a2->addr, sizeof (a1->addr));
1622}
1623
1624
77dd4c3b
UD
1625/* Name of the config file for RFC 3484 sorting (for now). */
1626#define GAICONF_FNAME "/etc/gai.conf"
1627
1628
fc4837e5 1629/* Non-zero if we are supposed to reload the config file automatically
77dd4c3b
UD
1630 whenever it changed. */
1631static int gaiconf_reload_flag;
1632
fc4837e5
UD
1633/* Non-zero if gaiconf_reload_flag was ever set to true. */
1634static int gaiconf_reload_flag_ever_set;
1635
77dd4c3b 1636/* Last modification time. */
a0844057
RM
1637#ifdef _STATBUF_ST_NSEC
1638
77dd4c3b
UD
1639static struct timespec gaiconf_mtime;
1640
a0844057
RM
1641static inline void
1642save_gaiconf_mtime (const struct stat64 *st)
1643{
1644 gaiconf_mtime = st->st_mtim;
1645}
1646
1647static inline bool
1648check_gaiconf_mtime (const struct stat64 *st)
1649{
1650 return (st->st_mtim.tv_sec == gaiconf_mtime.tv_sec
1651 && st->st_mtim.tv_nsec == gaiconf_mtime.tv_nsec);
1652}
1653
1654#else
1655
1656static time_t gaiconf_mtime;
1657
1658static inline void
1659save_gaiconf_mtime (const struct stat64 *st)
1660{
1661 gaiconf_mtime = st->st_mtime;
1662}
1663
1664static inline bool
1665check_gaiconf_mtime (const struct stat64 *st)
1666{
fbc723bb 1667 return st->st_mtime == gaiconf_mtime;
a0844057
RM
1668}
1669
1670#endif
1671
77dd4c3b
UD
1672
1673libc_freeres_fn(fini)
1674{
1675 if (labels != default_labels)
1676 {
1677 const struct prefixentry *old = labels;
1678 labels = default_labels;
1679 free ((void *) old);
1680 }
1681
1682 if (precedence != default_precedence)
1683 {
1684 const struct prefixentry *old = precedence;
1685 precedence = default_precedence;
1686 free ((void *) old);
1687 }
ee72b971
UD
1688
1689 if (scopes != default_scopes)
1690 {
1691 const struct scopeentry *old = scopes;
1692 scopes = default_scopes;
1693 free ((void *) old);
1694 }
77dd4c3b
UD
1695}
1696
1697
1698struct prefixlist
1699{
1700 struct prefixentry entry;
1701 struct prefixlist *next;
1702};
1703
1704
ee72b971
UD
1705struct scopelist
1706{
1707 struct scopeentry entry;
1708 struct scopelist *next;
1709};
1710
1711
77dd4c3b
UD
1712static void
1713free_prefixlist (struct prefixlist *list)
1714{
1715 while (list != NULL)
1716 {
1717 struct prefixlist *oldp = list;
1718 list = list->next;
1719 free (oldp);
1720 }
1721}
1722
1723
ee72b971
UD
1724static void
1725free_scopelist (struct scopelist *list)
1726{
1727 while (list != NULL)
1728 {
1729 struct scopelist *oldp = list;
1730 list = list->next;
1731 free (oldp);
1732 }
1733}
1734
1735
77dd4c3b
UD
1736static int
1737prefixcmp (const void *p1, const void *p2)
1738{
1739 const struct prefixentry *e1 = (const struct prefixentry *) p1;
1740 const struct prefixentry *e2 = (const struct prefixentry *) p2;
1741
1742 if (e1->bits < e2->bits)
1743 return 1;
1744 if (e1->bits == e2->bits)
1745 return 0;
1746 return -1;
1747}
1748
1749
ee72b971
UD
1750static int
1751scopecmp (const void *p1, const void *p2)
1752{
1753 const struct scopeentry *e1 = (const struct scopeentry *) p1;
1754 const struct scopeentry *e2 = (const struct scopeentry *) p2;
1755
1756 if (e1->netmask > e2->netmask)
1757 return -1;
1758 if (e1->netmask == e2->netmask)
1759 return 0;
1760 return 1;
1761}
1762
1763
77dd4c3b
UD
1764static void
1765gaiconf_init (void)
1766{
1767 struct prefixlist *labellist = NULL;
1768 size_t nlabellist = 0;
1769 bool labellist_nullbits = false;
1770 struct prefixlist *precedencelist = NULL;
1771 size_t nprecedencelist = 0;
1772 bool precedencelist_nullbits = false;
ee72b971
UD
1773 struct scopelist *scopelist = NULL;
1774 size_t nscopelist = 0;
1775 bool scopelist_nullbits = false;
77dd4c3b 1776
312be3f9 1777 FILE *fp = fopen (GAICONF_FNAME, "rce");
77dd4c3b
UD
1778 if (fp != NULL)
1779 {
1780 struct stat64 st;
04986243 1781 if (__fstat64 (fileno (fp), &st) != 0)
77dd4c3b
UD
1782 {
1783 fclose (fp);
1784 goto no_file;
1785 }
1786
1787 char *line = NULL;
1788 size_t linelen = 0;
1789
1790 __fsetlocking (fp, FSETLOCKING_BYCALLER);
1791
1792 while (!feof_unlocked (fp))
1793 {
1794 ssize_t n = __getline (&line, &linelen, fp);
1795 if (n <= 0)
1796 break;
1797
1798 /* Handle comments. No escaping possible so this is easy. */
1799 char *cp = strchr (line, '#');
1800 if (cp != NULL)
1801 *cp = '\0';
1802
1803 cp = line;
1804 while (isspace (*cp))
1805 ++cp;
1806
1807 char *cmd = cp;
1808 while (*cp != '\0' && !isspace (*cp))
1809 ++cp;
1810 size_t cmdlen = cp - cmd;
1811
1812 if (*cp != '\0')
1813 *cp++ = '\0';
1814 while (isspace (*cp))
1815 ++cp;
1816
1817 char *val1 = cp;
1818 while (*cp != '\0' && !isspace (*cp))
1819 ++cp;
1820 size_t val1len = cp - cmd;
1821
1822 /* We always need at least two values. */
1823 if (val1len == 0)
1824 continue;
1825
1826 if (*cp != '\0')
1827 *cp++ = '\0';
1828 while (isspace (*cp))
1829 ++cp;
1830
1831 char *val2 = cp;
1832 while (*cp != '\0' && !isspace (*cp))
1833 ++cp;
1834
1835 /* Ignore the rest of the line. */
1836 *cp = '\0';
1837
1838 struct prefixlist **listp;
1839 size_t *lenp;
1840 bool *nullbitsp;
1841 switch (cmdlen)
1842 {
1843 case 5:
1844 if (strcmp (cmd, "label") == 0)
1845 {
1846 struct in6_addr prefix;
ecc68568 1847 unsigned long int bits;
77dd4c3b
UD
1848 unsigned long int val;
1849 char *endp;
1850
1851 listp = &labellist;
1852 lenp = &nlabellist;
1853 nullbitsp = &labellist_nullbits;
1854
1855 new_elem:
ecc68568 1856 bits = 128;
77dd4c3b
UD
1857 __set_errno (0);
1858 cp = strchr (val1, '/');
1859 if (cp != NULL)
1860 *cp++ = '\0';
1861 if (inet_pton (AF_INET6, val1, &prefix)
1862 && (cp == NULL
1863 || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX
1864 || errno != ERANGE)
1865 && *endp == '\0'
ee72b971 1866 && bits <= 128
77dd4c3b
UD
1867 && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX
1868 || errno != ERANGE)
1869 && *endp == '\0'
1870 && val <= INT_MAX)
1871 {
1872 struct prefixlist *newp = malloc (sizeof (*newp));
1873 if (newp == NULL)
1874 {
1875 free (line);
1876 fclose (fp);
1877 goto no_file;
1878 }
1879
1880 memcpy (&newp->entry.prefix, &prefix, sizeof (prefix));
1881 newp->entry.bits = bits;
1882 newp->entry.val = val;
1883 newp->next = *listp;
1884 *listp = newp;
1885 ++*lenp;
1886 *nullbitsp |= bits == 0;
1887 }
1888 }
1889 break;
1890
1891 case 6:
1892 if (strcmp (cmd, "reload") == 0)
fc4837e5
UD
1893 {
1894 gaiconf_reload_flag = strcmp (val1, "yes") == 0;
1895 if (gaiconf_reload_flag)
1896 gaiconf_reload_flag_ever_set = 1;
1897 }
77dd4c3b
UD
1898 break;
1899
ee72b971
UD
1900 case 7:
1901 if (strcmp (cmd, "scopev4") == 0)
1902 {
1903 struct in6_addr prefix;
1904 unsigned long int bits;
1905 unsigned long int val;
1906 char *endp;
1907
1908 bits = 32;
1909 __set_errno (0);
1910 cp = strchr (val1, '/');
1911 if (cp != NULL)
1912 *cp++ = '\0';
1913 if (inet_pton (AF_INET6, val1, &prefix))
1914 {
fde15fdc 1915 bits = 128;
ee72b971
UD
1916 if (IN6_IS_ADDR_V4MAPPED (&prefix)
1917 && (cp == NULL
1918 || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX
1919 || errno != ERANGE)
1920 && *endp == '\0'
1921 && bits >= 96
1922 && bits <= 128
1923 && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX
1924 || errno != ERANGE)
1925 && *endp == '\0'
1926 && val <= INT_MAX)
1927 {
1928 struct scopelist *newp;
1929 new_scope:
1930 newp = malloc (sizeof (*newp));
1931 if (newp == NULL)
1932 {
1933 free (line);
1934 fclose (fp);
1935 goto no_file;
1936 }
1937
1938 newp->entry.netmask = htonl (bits != 96
1939 ? (0xffffffff
1940 << (128 - bits))
1941 : 0);
1942 newp->entry.addr32 = (prefix.s6_addr32[3]
1943 & newp->entry.netmask);
1944 newp->entry.scope = val;
1945 newp->next = scopelist;
1946 scopelist = newp;
1947 ++nscopelist;
1948 scopelist_nullbits |= bits == 96;
1949 }
1950 }
1951 else if (inet_pton (AF_INET, val1, &prefix.s6_addr32[3])
1952 && (cp == NULL
1953 || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX
1954 || errno != ERANGE)
1955 && *endp == '\0'
1956 && bits <= 32
1957 && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX
1958 || errno != ERANGE)
1959 && *endp == '\0'
1960 && val <= INT_MAX)
1961 {
1962 bits += 96;
1963 goto new_scope;
1964 }
1965 }
1966 break;
1967
77dd4c3b
UD
1968 case 10:
1969 if (strcmp (cmd, "precedence") == 0)
1970 {
1971 listp = &precedencelist;
1972 lenp = &nprecedencelist;
1973 nullbitsp = &precedencelist_nullbits;
1974 goto new_elem;
1975 }
1976 break;
1977 }
1978 }
1979
1980 free (line);
1981
1982 fclose (fp);
1983
1984 /* Create the array for the labels. */
1985 struct prefixentry *new_labels;
1986 if (nlabellist > 0)
1987 {
1988 if (!labellist_nullbits)
1989 ++nlabellist;
1990 new_labels = malloc (nlabellist * sizeof (*new_labels));
1991 if (new_labels == NULL)
1992 goto no_file;
1993
1994 int i = nlabellist;
1995 if (!labellist_nullbits)
1996 {
1997 --i;
1998 memset (&new_labels[i].prefix, '\0', sizeof (struct in6_addr));
1999 new_labels[i].bits = 0;
2000 new_labels[i].val = 1;
2001 }
2002
2003 struct prefixlist *l = labellist;
2004 while (i-- > 0)
2005 {
2006 new_labels[i] = l->entry;
2007 l = l->next;
2008 }
2009 free_prefixlist (labellist);
2010
2011 /* Sort the entries so that the most specific ones are at
2012 the beginning. */
2013 qsort (new_labels, nlabellist, sizeof (*new_labels), prefixcmp);
2014 }
2015 else
2016 new_labels = (struct prefixentry *) default_labels;
2017
2018 struct prefixentry *new_precedence;
2019 if (nprecedencelist > 0)
2020 {
2021 if (!precedencelist_nullbits)
2022 ++nprecedencelist;
2023 new_precedence = malloc (nprecedencelist * sizeof (*new_precedence));
2024 if (new_precedence == NULL)
2025 {
2026 if (new_labels != default_labels)
2027 free (new_labels);
2028 goto no_file;
2029 }
2030
2031 int i = nprecedencelist;
2032 if (!precedencelist_nullbits)
2033 {
2034 --i;
2035 memset (&new_precedence[i].prefix, '\0',
2036 sizeof (struct in6_addr));
2037 new_precedence[i].bits = 0;
2038 new_precedence[i].val = 40;
2039 }
2040
2041 struct prefixlist *l = precedencelist;
2042 while (i-- > 0)
2043 {
2044 new_precedence[i] = l->entry;
2045 l = l->next;
2046 }
2047 free_prefixlist (precedencelist);
2048
2049 /* Sort the entries so that the most specific ones are at
2050 the beginning. */
ee72b971 2051 qsort (new_precedence, nprecedencelist, sizeof (*new_precedence),
77dd4c3b
UD
2052 prefixcmp);
2053 }
2054 else
2055 new_precedence = (struct prefixentry *) default_precedence;
2056
ee72b971
UD
2057 struct scopeentry *new_scopes;
2058 if (nscopelist > 0)
2059 {
2060 if (!scopelist_nullbits)
2061 ++nscopelist;
2062 new_scopes = malloc (nscopelist * sizeof (*new_scopes));
2063 if (new_scopes == NULL)
2064 {
2065 if (new_labels != default_labels)
2066 free (new_labels);
2067 if (new_precedence != default_precedence)
2068 free (new_precedence);
2069 goto no_file;
2070 }
2071
2072 int i = nscopelist;
2073 if (!scopelist_nullbits)
2074 {
2075 --i;
2076 new_scopes[i].addr32 = 0;
2077 new_scopes[i].netmask = 0;
2078 new_scopes[i].scope = 14;
2079 }
2080
2081 struct scopelist *l = scopelist;
2082 while (i-- > 0)
2083 {
2084 new_scopes[i] = l->entry;
2085 l = l->next;
2086 }
2087 free_scopelist (scopelist);
2088
2089 /* Sort the entries so that the most specific ones are at
2090 the beginning. */
2091 qsort (new_scopes, nscopelist, sizeof (*new_scopes),
2092 scopecmp);
2093 }
2094 else
2095 new_scopes = (struct scopeentry *) default_scopes;
2096
77dd4c3b
UD
2097 /* Now we are ready to replace the values. */
2098 const struct prefixentry *old = labels;
2099 labels = new_labels;
2100 if (old != default_labels)
2101 free ((void *) old);
2102
2103 old = precedence;
2104 precedence = new_precedence;
2105 if (old != default_precedence)
2106 free ((void *) old);
2107
ee72b971
UD
2108 const struct scopeentry *oldscope = scopes;
2109 scopes = new_scopes;
2110 if (oldscope != default_scopes)
2111 free ((void *) oldscope);
2112
a0844057 2113 save_gaiconf_mtime (&st);
77dd4c3b
UD
2114 }
2115 else
2116 {
2117 no_file:
2118 free_prefixlist (labellist);
2119 free_prefixlist (precedencelist);
ee72b971 2120 free_scopelist (scopelist);
77dd4c3b
UD
2121
2122 /* If we previously read the file but it is gone now, free the
2123 old data and use the builtin one. Leave the reload flag
2124 alone. */
2125 fini ();
2126 }
2127}
2128
2129
2130static void
2131gaiconf_reload (void)
2132{
2133 struct stat64 st;
8ed005da 2134 if (__stat64 (GAICONF_FNAME, &st) != 0
a0844057 2135 || !check_gaiconf_mtime (&st))
77dd4c3b
UD
2136 gaiconf_init ();
2137}
2138
2139
40a55d20
UD
2140int
2141getaddrinfo (const char *name, const char *service,
2142 const struct addrinfo *hints, struct addrinfo **pai)
46ec036d 2143{
786dcb62 2144 int i = 0, last_i = 0;
5ddb5bf5 2145 int nresults = 0;
786dcb62 2146 struct addrinfo *p = NULL;
46ec036d 2147 struct gaih_service gaih_service, *pservice;
925c3c5c 2148 struct addrinfo local_hints;
46ec036d 2149
40a55d20 2150 if (name != NULL && name[0] == '*' && name[1] == 0)
1fb05e3d
UD
2151 name = NULL;
2152
40a55d20 2153 if (service != NULL && service[0] == '*' && service[1] == 0)
1fb05e3d
UD
2154 service = NULL;
2155
40a55d20 2156 if (name == NULL && service == NULL)
46ec036d
UD
2157 return EAI_NONAME;
2158
40a55d20
UD
2159 if (hints == NULL)
2160 hints = &default_hints;
46ec036d 2161
925c3c5c
UD
2162 if (hints->ai_flags
2163 & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|AI_ADDRCONFIG|AI_V4MAPPED
7f9f1ecb 2164 |AI_IDN|AI_CANONIDN|DEPRECATED_AI_IDN
c1d98085 2165 |AI_NUMERICSERV|AI_ALL))
46ec036d
UD
2166 return EAI_BADFLAGS;
2167
06877a37 2168 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
46ec036d
UD
2169 return EAI_BADFLAGS;
2170
c1de872c
TR
2171 if (hints->ai_family != AF_UNSPEC && hints->ai_family != AF_INET
2172 && hints->ai_family != AF_INET6)
2173 return EAI_FAMILY;
2174
cf6ada44 2175 struct in6addrinfo *in6ai = NULL;
e53f0f51 2176 size_t in6ailen = 0;
3af48b5b
UD
2177 bool seen_ipv4 = false;
2178 bool seen_ipv6 = false;
fa3fc0fe 2179 bool check_pf_called = false;
e53f0f51 2180
925c3c5c
UD
2181 if (hints->ai_flags & AI_ADDRCONFIG)
2182 {
fa3fc0fe
UD
2183 /* We might need information about what interfaces are available.
2184 Also determine whether we have IPv4 or IPv6 interfaces or both. We
2185 cannot cache the results since new interfaces could be added at
2186 any time. */
2187 __check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen);
2188 check_pf_called = true;
2189
925c3c5c 2190 /* Now make a decision on what we return, if anything. */
c1d98085 2191 if (hints->ai_family == PF_UNSPEC && (seen_ipv4 || seen_ipv6))
925c3c5c
UD
2192 {
2193 /* If we haven't seen both IPv4 and IPv6 interfaces we can
2194 narrow down the search. */
cceb038a 2195 if (seen_ipv4 != seen_ipv6)
925c3c5c
UD
2196 {
2197 local_hints = *hints;
2198 local_hints.ai_family = seen_ipv4 ? PF_INET : PF_INET6;
2199 hints = &local_hints;
2200 }
2201 }
2202 else if ((hints->ai_family == PF_INET && ! seen_ipv4)
2203 || (hints->ai_family == PF_INET6 && ! seen_ipv6))
3af48b5b
UD
2204 {
2205 /* We cannot possibly return a valid answer. */
3a2c0242 2206 __free_in6ai (in6ai);
3af48b5b
UD
2207 return EAI_NONAME;
2208 }
925c3c5c
UD
2209 }
2210
40a55d20
UD
2211 if (service && service[0])
2212 {
2213 char *c;
2214 gaih_service.name = service;
2215 gaih_service.num = strtoul (gaih_service.name, &c, 10);
c1d98085
UD
2216 if (*c != '\0')
2217 {
2218 if (hints->ai_flags & AI_NUMERICSERV)
3af48b5b 2219 {
3a2c0242 2220 __free_in6ai (in6ai);
3af48b5b
UD
2221 return EAI_NONAME;
2222 }
c1d98085
UD
2223
2224 gaih_service.num = -1;
2225 }
ca225a41 2226
40a55d20
UD
2227 pservice = &gaih_service;
2228 }
2229 else
46ec036d
UD
2230 pservice = NULL;
2231
d0a1ae94 2232 struct addrinfo **end = &p;
01abbc0f 2233 unsigned int naddrs = 0;
c1de872c 2234 struct scratch_buffer tmpbuf;
cd065b68 2235
c1de872c
TR
2236 scratch_buffer_init (&tmpbuf);
2237 last_i = gaih_inet (name, pservice, hints, end, &naddrs, &tmpbuf);
2238 scratch_buffer_free (&tmpbuf);
786dcb62 2239
c1de872c 2240 if (last_i != 0)
786dcb62 2241 {
c1de872c 2242 freeaddrinfo (p);
3a2c0242 2243 __free_in6ai (in6ai);
c1de872c
TR
2244
2245 return -last_i;
2246 }
2247
2248 while (*end)
2249 {
2250 end = &((*end)->ai_next);
2251 ++nresults;
786dcb62 2252 }
46ec036d 2253
01abbc0f 2254 if (naddrs > 1)
5ddb5bf5 2255 {
77dd4c3b
UD
2256 /* Read the config file. */
2257 __libc_once_define (static, once);
2258 __typeof (once) old_once = once;
2259 __libc_once (once, gaiconf_init);
5ddb5bf5 2260 /* Sort results according to RFC 3484. */
1cef1b19
AS
2261 struct sort_result *results;
2262 size_t *order;
5ddb5bf5 2263 struct addrinfo *q;
d19687d6 2264 struct addrinfo *last = NULL;
c7fa647a 2265 char *canonname = NULL;
1cef1b19 2266 bool malloc_results;
2169712d 2267 size_t alloc_size = nresults * (sizeof (*results) + sizeof (size_t));
1cef1b19
AS
2268
2269 malloc_results
2169712d 2270 = !__libc_use_alloca (alloc_size);
1cef1b19
AS
2271 if (malloc_results)
2272 {
2169712d 2273 results = malloc (alloc_size);
1cef1b19
AS
2274 if (results == NULL)
2275 {
2276 __free_in6ai (in6ai);
2277 return EAI_MEMORY;
2278 }
2279 }
2280 else
2169712d 2281 results = alloca (alloc_size);
1cef1b19 2282 order = (size_t *) (results + nresults);
5ddb5bf5 2283
fa3fc0fe
UD
2284 /* Now we definitely need the interface information. */
2285 if (! check_pf_called)
2286 __check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen);
2287
773e79b3 2288 /* If we have information about deprecated and temporary addresses
3af48b5b
UD
2289 sort the array now. */
2290 if (in6ai != NULL)
2291 qsort (in6ai, in6ailen, sizeof (*in6ai), in6aicmp);
2292
e1db0493
UD
2293 int fd = -1;
2294 int af = AF_UNSPEC;
2295
d19687d6 2296 for (i = 0, q = p; q != NULL; ++i, last = q, q = q->ai_next)
5ddb5bf5
UD
2297 {
2298 results[i].dest_addr = q;
773e79b3 2299 results[i].native = -1;
0efd1956 2300 order[i] = i;
5ddb5bf5 2301
007a3ddc 2302 /* If we just looked up the address for a different
d19687d6
UD
2303 protocol, reuse the result. */
2304 if (last != NULL && last->ai_addrlen == q->ai_addrlen
2305 && memcmp (last->ai_addr, q->ai_addr, q->ai_addrlen) == 0)
5ddb5bf5 2306 {
d19687d6
UD
2307 memcpy (&results[i].source_addr, &results[i - 1].source_addr,
2308 results[i - 1].source_addr_len);
2309 results[i].source_addr_len = results[i - 1].source_addr_len;
2310 results[i].got_source_addr = results[i - 1].got_source_addr;
3af48b5b 2311 results[i].source_addr_flags = results[i - 1].source_addr_flags;
6f3914d5 2312 results[i].prefixlen = results[i - 1].prefixlen;
773e79b3 2313 results[i].index = results[i - 1].index;
d19687d6
UD
2314 }
2315 else
2316 {
6f3914d5 2317 results[i].got_source_addr = false;
3af48b5b 2318 results[i].source_addr_flags = 0;
6f3914d5 2319 results[i].prefixlen = 0;
773e79b3 2320 results[i].index = 0xffffffffu;
3af48b5b 2321
007a3ddc
UD
2322 /* We overwrite the type with SOCK_DGRAM since we do not
2323 want connect() to connect to the other side. If we
2324 cannot determine the source address remember this
2325 fact. */
e1db0493
UD
2326 if (fd == -1 || (af == AF_INET && q->ai_family == AF_INET6))
2327 {
2328 if (fd != -1)
2329 close_retry:
c181840c 2330 __close_nocancel_nostatus (fd);
e1db0493 2331 af = q->ai_family;
2f83a729 2332 fd = __socket (af, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_IP);
e1db0493
UD
2333 }
2334 else
2335 {
2336 /* Reset the connection. */
2337 struct sockaddr sa = { .sa_family = AF_UNSPEC };
2338 __connect (fd, &sa, sizeof (sa));
2339 }
2340
007a3ddc
UD
2341 socklen_t sl = sizeof (results[i].source_addr);
2342 if (fd != -1
2343 && __connect (fd, q->ai_addr, q->ai_addrlen) == 0
2344 && __getsockname (fd,
2345 (struct sockaddr *) &results[i].source_addr,
2346 &sl) == 0)
d19687d6 2347 {
007a3ddc
UD
2348 results[i].source_addr_len = sl;
2349 results[i].got_source_addr = true;
3af48b5b 2350
6f3914d5 2351 if (in6ai != NULL)
3af48b5b 2352 {
e1db0493 2353 /* See whether the source address is on the list of
11bf311e 2354 deprecated or temporary addresses. */
3af48b5b 2355 struct in6addrinfo tmp;
6f3914d5
UD
2356
2357 if (q->ai_family == AF_INET && af == AF_INET)
2358 {
2359 struct sockaddr_in *sinp
2360 = (struct sockaddr_in *) &results[i].source_addr;
2361 tmp.addr[0] = 0;
2362 tmp.addr[1] = 0;
2363 tmp.addr[2] = htonl (0xffff);
894f3f10
AM
2364 /* Special case for lo interface, the source address
2365 being possibly different than the interface
2366 address. */
2367 if ((ntohl(sinp->sin_addr.s_addr) & 0xff000000)
2368 == 0x7f000000)
2369 tmp.addr[3] = htonl(0x7f000001);
2370 else
2371 tmp.addr[3] = sinp->sin_addr.s_addr;
6f3914d5
UD
2372 }
2373 else
2374 {
2375 struct sockaddr_in6 *sin6p
2376 = (struct sockaddr_in6 *) &results[i].source_addr;
2377 memcpy (tmp.addr, &sin6p->sin6_addr, IN6ADDRSZ);
2378 }
3af48b5b
UD
2379
2380 struct in6addrinfo *found
2381 = bsearch (&tmp, in6ai, in6ailen, sizeof (*in6ai),
2382 in6aicmp);
2383 if (found != NULL)
6f3914d5
UD
2384 {
2385 results[i].source_addr_flags = found->flags;
2386 results[i].prefixlen = found->prefixlen;
773e79b3 2387 results[i].index = found->index;
6f3914d5 2388 }
3af48b5b 2389 }
6f3914d5
UD
2390
2391 if (q->ai_family == AF_INET && af == AF_INET6)
e1db0493
UD
2392 {
2393 /* We have to convert the address. The socket is
2394 IPv6 and the request is for IPv4. */
2395 struct sockaddr_in6 *sin6
2396 = (struct sockaddr_in6 *) &results[i].source_addr;
2397 struct sockaddr_in *sin
2398 = (struct sockaddr_in *) &results[i].source_addr;
2399 assert (IN6_IS_ADDR_V4MAPPED (sin6->sin6_addr.s6_addr32));
6f3914d5
UD
2400 sin->sin_family = AF_INET;
2401 /* We do not have to initialize sin_port since this
2402 fields has the same position and size in the IPv6
2403 structure. */
2404 assert (offsetof (struct sockaddr_in, sin_port)
2405 == offsetof (struct sockaddr_in6, sin6_port));
2406 assert (sizeof (sin->sin_port)
2407 == sizeof (sin6->sin6_port));
e1db0493
UD
2408 memcpy (&sin->sin_addr,
2409 &sin6->sin6_addr.s6_addr32[3], INADDRSZ);
6f3914d5 2410 results[i].source_addr_len = sizeof (struct sockaddr_in);
e1db0493 2411 }
d19687d6 2412 }
e1db0493
UD
2413 else if (errno == EAFNOSUPPORT && af == AF_INET6
2414 && q->ai_family == AF_INET)
2415 /* This could mean IPv6 sockets are IPv6-only. */
2416 goto close_retry;
007a3ddc
UD
2417 else
2418 /* Just make sure that if we have to process the same
2419 address again we do not copy any memory. */
2420 results[i].source_addr_len = 0;
5ddb5bf5 2421 }
c7fa647a
UD
2422
2423 /* Remember the canonical name. */
2424 if (q->ai_canonname != NULL)
2425 {
2426 assert (canonname == NULL);
2427 canonname = q->ai_canonname;
2428 q->ai_canonname = NULL;
2429 }
5ddb5bf5
UD
2430 }
2431
e1db0493 2432 if (fd != -1)
c181840c 2433 __close_nocancel_nostatus (fd);
e1db0493 2434
5ddb5bf5
UD
2435 /* We got all the source addresses we can get, now sort using
2436 the information. */
773e79b3
UD
2437 struct sort_result_combo src
2438 = { .results = results, .nresults = nresults };
a1ffb40e 2439 if (__glibc_unlikely (gaiconf_reload_flag_ever_set))
fc4837e5
UD
2440 {
2441 __libc_lock_define_initialized (static, lock);
2442
2443 __libc_lock_lock (lock);
be971a2b 2444 if (__libc_once_get (old_once) && gaiconf_reload_flag)
fc4837e5 2445 gaiconf_reload ();
bef8fd60 2446 __qsort_r (order, nresults, sizeof (order[0]), rfc3484_sort, &src);
fc4837e5
UD
2447 __libc_lock_unlock (lock);
2448 }
2449 else
bef8fd60 2450 __qsort_r (order, nresults, sizeof (order[0]), rfc3484_sort, &src);
5ddb5bf5
UD
2451
2452 /* Queue the results up as they come out of sorting. */
0efd1956 2453 q = p = results[order[0]].dest_addr;
5ddb5bf5 2454 for (i = 1; i < nresults; ++i)
0efd1956 2455 q = q->ai_next = results[order[i]].dest_addr;
5ddb5bf5 2456 q->ai_next = NULL;
c7fa647a
UD
2457
2458 /* Fill in the canonical name into the new first entry. */
2459 p->ai_canonname = canonname;
1cef1b19
AS
2460
2461 if (malloc_results)
2462 free (results);
5ddb5bf5
UD
2463 }
2464
3a2c0242 2465 __free_in6ai (in6ai);
3af48b5b 2466
40a55d20
UD
2467 if (p)
2468 {
2469 *pai = p;
2470 return 0;
2471 }
46ec036d 2472
639a0ef8 2473 return last_i ? -last_i : EAI_NONAME;
46ec036d 2474}
9b0b40d3 2475libc_hidden_def (getaddrinfo)
46ec036d 2476
01767843 2477nss_interface_function (getaddrinfo)
2f7f7bc6 2478
40a55d20
UD
2479void
2480freeaddrinfo (struct addrinfo *ai)
46ec036d
UD
2481{
2482 struct addrinfo *p;
2483
40a55d20
UD
2484 while (ai != NULL)
2485 {
2486 p = ai;
2487 ai = ai->ai_next;
b9343764 2488 free (p->ai_canonname);
40a55d20
UD
2489 free (p);
2490 }
46ec036d 2491}
9b0b40d3 2492libc_hidden_def (freeaddrinfo)