]> sourceware.org Git - glibc.git/blame - sysdeps/posix/getaddrinfo.c
Update.
[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>
c0bc5f7b 43#include <stdio.h>
46ec036d 44#include <stdlib.h>
c0bc5f7b 45#include <string.h>
1fb05e3d 46#include <unistd.h>
c0bc5f7b 47#include <arpa/inet.h>
1fb05e3d 48#include <sys/socket.h>
46ec036d 49#include <netinet/in.h>
c0bc5f7b
UD
50#include <sys/types.h>
51#include <sys/un.h>
52#include <sys/utsname.h>
4fcddf8e 53#include <net/if.h>
218d76e0 54#include <nsswitch.h>
1fb05e3d 55
46ec036d
UD
56#define GAIH_OKIFUNSPEC 0x0100
57#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
58
40a55d20
UD
59#ifndef UNIX_PATH_MAX
60#define UNIX_PATH_MAX 108
61#endif
46ec036d 62
40a55d20
UD
63struct gaih_service
64 {
65 const char *name;
66 int num;
67 };
46ec036d 68
40a55d20
UD
69struct gaih_servtuple
70 {
71 struct gaih_servtuple *next;
72 int socktype;
73 int protocol;
74 int port;
75 };
46ec036d 76
3e2d61a3 77static const struct gaih_servtuple nullserv;
46ec036d 78
40a55d20
UD
79struct gaih_addrtuple
80 {
81 struct gaih_addrtuple *next;
82 int family;
83 char addr[16];
c0bc5f7b 84 uint32_t scopeid;
40a55d20 85 };
46ec036d 86
40a55d20
UD
87struct gaih_typeproto
88 {
89 int socktype;
90 int protocol;
3e2d61a3 91 char name[4];
f3ac48d0 92 int protoflag;
40a55d20 93 };
46ec036d 94
f3ac48d0
UD
95/* Values for `protoflag'. */
96#define GAI_PROTO_NOSERVICE 1
85599e53 97#define GAI_PROTO_PROTOANY 2
f3ac48d0 98
3e2d61a3 99static const struct gaih_typeproto gaih_inet_typeproto[] =
40a55d20 100{
3e2d61a3
UD
101 { 0, 0, "", 0 },
102 { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
103 { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
104 { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
105 { 0, 0, "", 0 }
46ec036d
UD
106};
107
40a55d20
UD
108struct gaih
109 {
110 int family;
111 int (*gaih)(const char *name, const struct gaih_service *service,
112 const struct addrinfo *req, struct addrinfo **pai);
113 };
114
3e2d61a3 115static const struct addrinfo default_hints =
925c3c5c
UD
116 {
117 .ai_flags = AI_DEFAULT,
118 .ai_family = PF_UNSPEC,
119 .ai_socktype = 0,
120 .ai_protocol = 0,
121 .ai_addrlen = 0,
122 .ai_addr = NULL,
123 .ai_canonname = NULL,
124 .ai_next = NULL
125 };
40a55d20
UD
126
127
64b7897d
UD
128#if 0
129/* Using Unix sockets this way is a security risk. */
40a55d20
UD
130static int
131gaih_local (const char *name, const struct gaih_service *service,
132 const struct addrinfo *req, struct addrinfo **pai)
1fb05e3d
UD
133{
134 struct utsname utsname;
135
f1a785ac
UD
136 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
137 return GAIH_OKIFUNSPEC | -EAI_NONAME;
138
40a55d20 139 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
db7dc811 140 if (uname (&utsname) < 0)
1fb05e3d 141 return -EAI_SYSTEM;
1fb05e3d 142
40a55d20
UD
143 if (name != NULL)
144 {
145 if (strcmp(name, "localhost") &&
146 strcmp(name, "local") &&
147 strcmp(name, "unix") &&
148 strcmp(name, utsname.nodename))
149 return GAIH_OKIFUNSPEC | -EAI_NONAME;
150 }
151
a0bf6ac7
UD
152 if (req->ai_protocol || req->ai_socktype)
153 {
3e2d61a3 154 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
f3ac48d0 155
4b1fef84 156 while (tp->name[0]
f3ac48d0 157 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
3a47453d
UD
158 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
159 || (req->ai_protocol != 0
85599e53 160 && !(tp->protoflag & GAI_PROTO_PROTOANY)
3a47453d 161 && req->ai_protocol != tp->protocol)))
f3ac48d0 162 ++tp;
a0bf6ac7 163
4b1fef84 164 if (! tp->name[0])
a0bf6ac7
UD
165 {
166 if (req->ai_socktype)
167 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
168 else
169 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
170 }
171 }
172
173 *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
40a55d20
UD
174 + ((req->ai_flags & AI_CANONNAME)
175 ? (strlen(utsname.nodename) + 1): 0));
176 if (*pai == NULL)
1fb05e3d
UD
177 return -EAI_MEMORY;
178
179 (*pai)->ai_next = NULL;
180 (*pai)->ai_flags = req->ai_flags;
181 (*pai)->ai_family = AF_LOCAL;
182 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
183 (*pai)->ai_protocol = req->ai_protocol;
a0bf6ac7
UD
184 (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
185 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
40a55d20 186
1fb05e3d 187#if SALEN
40a55d20
UD
188 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
189 sizeof (struct sockaddr_un);
1fb05e3d 190#endif /* SALEN */
40a55d20 191
1fb05e3d
UD
192 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
193 memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
40a55d20
UD
194
195 if (service)
196 {
197 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
198
199 if (strchr (service->name, '/') != NULL)
200 {
201 if (strlen (service->name) >= sizeof (sunp->sun_path))
202 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
203
204 strcpy (sunp->sun_path, service->name);
205 }
206 else
207 {
208 if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
209 sizeof (sunp->sun_path))
210 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
211
212 __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
213 }
214 }
215 else
216 {
e658b54e
UD
217 /* This is a dangerous use of the interface since there is a time
218 window between the test for the file and the actual creation
219 (done by the caller) in which a file with the same name could
220 be created. */
221 char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
222
223 if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
224 0) != 0
225 || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
40a55d20
UD
226 return -EAI_SYSTEM;
227 }
228
1fb05e3d 229 if (req->ai_flags & AI_CANONNAME)
a0bf6ac7
UD
230 (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
231 + sizeof (struct sockaddr_un),
232 utsname.nodename);
1fb05e3d
UD
233 else
234 (*pai)->ai_canonname = NULL;
235 return 0;
40a55d20 236}
64b7897d 237#endif /* 0 */
46ec036d 238
40a55d20 239static int
3e2d61a3 240gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
85599e53 241 const struct addrinfo *req, struct gaih_servtuple *st)
46ec036d
UD
242{
243 struct servent *s;
40a55d20 244 size_t tmpbuflen = 1024;
993b3242 245 struct servent ts;
40a55d20
UD
246 char *tmpbuf;
247 int r;
248
249 do
993b3242 250 {
40a55d20 251 tmpbuf = __alloca (tmpbuflen);
40a55d20
UD
252
253 r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
254 &s);
a0bf6ac7 255 if (r != 0 || s == NULL)
993b3242 256 {
a0bf6ac7 257 if (r == ERANGE)
40a55d20
UD
258 tmpbuflen *= 2;
259 else
260 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
993b3242
UD
261 }
262 }
40a55d20 263 while (r);
993b3242 264
238ae1eb
UD
265 st->next = NULL;
266 st->socktype = tp->socktype;
85599e53
UD
267 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
268 ? req->ai_protocol : tp->protocol);
238ae1eb 269 st->port = s->s_port;
46ec036d
UD
270
271 return 0;
272}
273
925c3c5c
UD
274#define gethosts(_family, _type) \
275 { \
276 int i, herrno; \
277 size_t tmpbuflen; \
278 struct hostent th; \
279 char *tmpbuf = NULL; \
280 tmpbuflen = 512; \
281 no_data = 0; \
282 do { \
283 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \
284 rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \
285 tmpbuflen, &h, &herrno); \
286 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
287 if (rc != 0) \
288 { \
289 if (herrno == NETDB_INTERNAL) \
290 { \
291 __set_h_errno (herrno); \
292 return -EAI_SYSTEM; \
293 } \
294 if (herrno == TRY_AGAIN) \
295 no_data = EAI_AGAIN; \
296 else \
297 no_data = herrno == NO_DATA; \
298 } \
299 else if (h != NULL) \
300 { \
301 for (i = 0; h->h_addr_list[i]; i++) \
302 { \
303 if (*pat == NULL) { \
304 *pat = __alloca (sizeof (struct gaih_addrtuple)); \
305 (*pat)->scopeid = 0; \
306 } \
307 (*pat)->next = NULL; \
308 (*pat)->family = _family; \
309 memcpy ((*pat)->addr, h->h_addr_list[i], \
310 sizeof(_type)); \
311 pat = &((*pat)->next); \
312 } \
313 if (_family == AF_INET6) \
314 got_ipv6 = true; \
315 } \
316 else if (_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED)) \
317 { \
318 /* We have to add V4 mapped addresses. Maybe we discard them \
319 later again but we get them anyhow for now. */ \
320 while ((rc = __gethostbyname2_r (name, AF_INET6, &th, tmpbuf, \
321 tmpbuflen, &h, &herrno)) == ERANGE \
322 && herrno == NETDB_INTERNAL) \
323 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \
324 \
325 if (rc != 0) \
326 { \
327 if (herrno == NETDB_INTERNAL) \
328 { \
329 __set_h_errno (herrno); \
330 return -EAI_SYSTEM; \
331 } \
332 if (herrno == TRY_AGAIN) \
333 no_data = EAI_AGAIN; \
334 else \
335 no_data = herrno == NO_DATA; \
336 } \
337 else if (h != NULL) \
338 { \
339 for (i = 0; h->h_addr_list[i]; ++i) \
340 { \
341 if (*pat == NULL) \
342 { \
343 *pat = __alloca (sizeof (struct gaih_addrtuple)); \
344 (*pat)->scopeid = 0; \
345 } \
346 uint32_t *addr = (uint32_t *) (*pat)->addr; \
347 (*pat)->next = NULL; \
348 (*pat)->family = _family; \
349 addr[3] = *(uint32_t *) h->h_addr_list[i]; \
350 addr[2] = htonl (0xffff); \
351 addr[1] = 0; \
352 addr[0] = 0; \
353 pat = &((*pat)->next); \
354 } \
355 } \
356 } \
40a55d20
UD
357 }
358
925c3c5c
UD
359
360#define gethosts2(_family, _type) \
361 { \
362 int i, herrno; \
363 size_t tmpbuflen; \
364 struct hostent th; \
365 char *tmpbuf = NULL; \
366 tmpbuflen = 512; \
367 no_data = 0; \
368 do { \
369 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \
370 rc = 0; \
371 status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf, \
372 tmpbuflen, &rc, &herrno)); \
373 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
374 if (status == NSS_STATUS_SUCCESS && rc == 0) \
375 h = &th; \
376 else \
377 h = NULL; \
378 if (rc != 0) \
379 { \
380 if (herrno == NETDB_INTERNAL) \
381 { \
382 __set_h_errno (herrno); \
383 return -EAI_SYSTEM; \
384 } \
385 if (herrno == TRY_AGAIN) \
386 no_data = EAI_AGAIN; \
387 else \
388 no_data = herrno == NO_DATA; \
389 } \
390 else if (h != NULL) \
391 { \
392 for (i = 0; h->h_addr_list[i]; i++) \
393 { \
394 if (*pat == NULL) { \
395 *pat = __alloca (sizeof (struct gaih_addrtuple)); \
396 (*pat)->scopeid = 0; \
397 } \
398 (*pat)->next = NULL; \
399 (*pat)->family = _family; \
400 memcpy ((*pat)->addr, h->h_addr_list[i], \
401 sizeof(_type)); \
402 pat = &((*pat)->next); \
403 } \
404 } \
218d76e0
UD
405 }
406
407typedef enum nss_status (*nss_gethostbyname2_r)
408 (const char *name, int af, struct hostent *host,
409 char *buffer, size_t buflen, int *errnop,
410 int *h_errnop);
411extern service_user *__nss_hosts_database attribute_hidden;
412
40a55d20
UD
413static int
414gaih_inet (const char *name, const struct gaih_service *service,
415 const struct addrinfo *req, struct addrinfo **pai)
46ec036d 416{
3e2d61a3
UD
417 const struct gaih_typeproto *tp = gaih_inet_typeproto;
418 struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
1fb05e3d 419 struct gaih_addrtuple *at = NULL;
40a55d20 420 int rc;
925c3c5c 421 bool got_ipv6 = false;
46ec036d 422
40a55d20
UD
423 if (req->ai_protocol || req->ai_socktype)
424 {
f3ac48d0
UD
425 ++tp;
426
4b1fef84 427 while (tp->name[0]
3a47453d
UD
428 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
429 || (req->ai_protocol != 0
85599e53 430 && !(tp->protoflag & GAI_PROTO_PROTOANY)
3a47453d 431 && req->ai_protocol != tp->protocol)))
f3ac48d0
UD
432 ++tp;
433
4b1fef84 434 if (! tp->name[0])
6e4c40ba
UD
435 {
436 if (req->ai_socktype)
437 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
438 else
439 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
440 }
40a55d20
UD
441 }
442
443 if (service != NULL)
444 {
f3ac48d0
UD
445 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
446 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
447
40a55d20
UD
448 if (service->num < 0)
449 {
4b1fef84 450 if (tp->name[0])
40a55d20 451 {
238ae1eb
UD
452 st = (struct gaih_servtuple *)
453 __alloca (sizeof (struct gaih_servtuple));
454
85599e53 455 if ((rc = gaih_inet_serv (service->name, tp, req, st)))
40a55d20
UD
456 return rc;
457 }
458 else
459 {
460 struct gaih_servtuple **pst = &st;
4b1fef84 461 for (tp++; tp->name[0]; tp++)
40a55d20 462 {
3a47453d
UD
463 struct gaih_servtuple *newp;
464
465 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
466 continue;
467
84a4fd33
UD
468 if (req->ai_socktype != 0
469 && req->ai_socktype != tp->socktype)
470 continue;
85599e53
UD
471 if (req->ai_protocol != 0
472 && !(tp->protoflag & GAI_PROTO_PROTOANY)
473 && req->ai_protocol != tp->protocol)
474 continue;
84a4fd33 475
3a47453d 476 newp = (struct gaih_servtuple *)
238ae1eb
UD
477 __alloca (sizeof (struct gaih_servtuple));
478
85599e53 479 if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
40a55d20
UD
480 {
481 if (rc & GAIH_OKIFUNSPEC)
482 continue;
483 return rc;
484 }
238ae1eb
UD
485
486 *pst = newp;
487 pst = &(newp->next);
40a55d20 488 }
3e2d61a3 489 if (st == (struct gaih_servtuple *) &nullserv)
40a55d20
UD
490 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
491 }
46ec036d 492 }
40a55d20
UD
493 else
494 {
a0bf6ac7 495 st = __alloca (sizeof (struct gaih_servtuple));
40a55d20
UD
496 st->next = NULL;
497 st->socktype = tp->socktype;
85599e53
UD
498 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
499 ? req->ai_protocol : tp->protocol);
40a55d20 500 st->port = htons (service->num);
46ec036d 501 }
40a55d20 502 }
84a4fd33
UD
503 else if (req->ai_socktype || req->ai_protocol)
504 {
505 st = __alloca (sizeof (struct gaih_servtuple));
506 st->next = NULL;
85599e53
UD
507 st->socktype = tp->socktype;
508 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
509 ? req->ai_protocol : tp->protocol);
84a4fd33
UD
510 st->port = 0;
511 }
512 else
513 {
514 /* Neither socket type nor protocol is set. Return all socket types
515 we know about. */
516 struct gaih_servtuple **lastp = &st;
4b1fef84 517 for (++tp; tp->name[0]; ++tp)
84a4fd33
UD
518 {
519 struct gaih_servtuple *newp;
520
521 newp = __alloca (sizeof (struct gaih_servtuple));
522 newp->next = NULL;
523 newp->socktype = tp->socktype;
524 newp->protocol = tp->protocol;
525 newp->port = 0;
526
527 *lastp = newp;
528 lastp = &newp->next;
529 }
530 }
40a55d20
UD
531
532 if (name != NULL)
533 {
a0bf6ac7 534 at = __alloca (sizeof (struct gaih_addrtuple));
46ec036d 535
a0bf6ac7 536 at->family = AF_UNSPEC;
c0bc5f7b 537 at->scopeid = 0;
40a55d20 538 at->next = NULL;
46ec036d 539
a0bf6ac7
UD
540 if (inet_pton (AF_INET, name, at->addr) > 0)
541 {
542 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
543 at->family = AF_INET;
925c3c5c
UD
544 else if (req->ai_flags & AI_V4MAPPED)
545 {
546 ((uint32_t *) at->addr)[3] = *(uint32_t *) at->addr;
547 ((uint32_t *) at->addr)[2] = htonl (0xffff);
548 ((uint32_t *) at->addr)[1] = 0;
549 ((uint32_t *) at->addr)[0] = 0;
550 }
a0bf6ac7
UD
551 else
552 return -EAI_ADDRFAMILY;
553 }
46ec036d 554
c0bc5f7b 555 if (at->family == AF_UNSPEC)
a0bf6ac7 556 {
c0bc5f7b
UD
557 char *namebuf = strdupa (name);
558 char *scope_delim;
559
560 scope_delim = strchr (namebuf, SCOPE_DELIMITER);
561 if (scope_delim != NULL)
562 *scope_delim = '\0';
563
564 if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
565 {
c0bc5f7b
UD
566 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
567 at->family = AF_INET6;
925c3c5c
UD
568 else if (IN6_IS_ADDR_V4MAPPED (at->addr))
569 *(uint32_t *) at->addr = ((uint32_t *) at->addr)[3];
c0bc5f7b
UD
570 else
571 return -EAI_ADDRFAMILY;
572
573 if (scope_delim != NULL)
574 {
575 int try_numericscope = 0;
576 if (IN6_IS_ADDR_LINKLOCAL (at->addr)
577 || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
578 {
579 at->scopeid = if_nametoindex (scope_delim + 1);
580 if (at->scopeid == 0)
581 try_numericscope = 1;
582 }
583 else
584 try_numericscope = 1;
585
586 if (try_numericscope != 0)
587 {
588 char *end;
589 assert (sizeof (uint32_t) <= sizeof (unsigned long));
590 at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
591 10);
592 if (*end != '\0')
593 return GAIH_OKIFUNSPEC | -EAI_NONAME;
594 }
595 }
596 }
a0bf6ac7 597 }
40a55d20 598
ce75c139 599 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
40a55d20
UD
600 {
601 struct hostent *h;
602 struct gaih_addrtuple **pat = &at;
a0bf6ac7 603 int no_data = 0;
218d76e0 604 int no_inet6_data = 0;
9c42c64d
UD
605 int old_res_options = _res.options;
606
607 /* If we are looking for both IPv4 and IPv6 address we don't
608 want the lookup functions to automatically promote IPv4
609 addresses to IPv6 addresses. Currently this is decided
610 by setting the RES_USE_INET6 bit in _res.options. */
611 if (req->ai_family == AF_UNSPEC)
218d76e0
UD
612 {
613 service_user *nip = NULL;
614 enum nss_status inet6_status, status = NSS_STATUS_UNAVAIL;
615 int no_more;
616 nss_gethostbyname2_r fct;
40a55d20 617
218d76e0
UD
618 if (__nss_hosts_database != NULL)
619 {
620 no_more = 0;
621 nip = __nss_hosts_database;
622 }
623 else
624 no_more = __nss_database_lookup ("hosts", NULL,
625 "dns [!UNAVAIL=return] files", &nip);
40a55d20 626
218d76e0 627 _res.options &= ~RES_USE_INET6;
9c42c64d 628
218d76e0
UD
629 while (!no_more)
630 {
631 fct = __nss_lookup_function (nip, "gethostbyname2_r");
632
64ab2317
UD
633 if (fct != NULL)
634 {
635 gethosts2 (AF_INET6, struct in6_addr);
636 no_inet6_data = no_data;
637 inet6_status = status;
638 gethosts2 (AF_INET, struct in_addr);
639
640 /* If we found one address for AF_INET or AF_INET6,
641 don't continue the search. */
642 if (inet6_status == NSS_STATUS_SUCCESS ||
643 status == NSS_STATUS_SUCCESS)
644 break;
645
646 /* We can have different states for AF_INET
647 and AF_INET6. Try to find a usefull one for
648 both. */
649 if (inet6_status == NSS_STATUS_TRYAGAIN)
650 status = NSS_STATUS_TRYAGAIN;
651 else if (status == NSS_STATUS_UNAVAIL &&
652 inet6_status != NSS_STATUS_UNAVAIL)
653 status = inet6_status;
654 }
218d76e0
UD
655
656 if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
657 break;
658
659 if (nip->next == NULL)
660 no_more = -1;
661 else
662 nip = nip->next;
663 }
664
665 _res.options = old_res_options;
666 }
667 else if (req->ai_family == AF_INET6)
668 {
669 gethosts (AF_INET6, struct in6_addr);
670 no_inet6_data = no_data;
671 }
672 else if (req->ai_family == AF_INET)
40a55d20 673 gethosts (AF_INET, struct in_addr);
a0bf6ac7 674
5ad81f40 675 if (no_data != 0 && no_inet6_data != 0)
7813b61a
UD
676 {
677 /* If both requests timed out report this. */
678 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
679 return -EAI_AGAIN;
680
681 /* We made requests but they turned out no data. The name
682 is known, though. */
683 return (GAIH_OKIFUNSPEC | -EAI_NODATA);
684 }
46ec036d 685 }
40a55d20
UD
686
687 if (at->family == AF_UNSPEC)
688 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
46ec036d 689 }
40a55d20
UD
690 else
691 {
7396d844 692 struct gaih_addrtuple *atr;
a0bf6ac7
UD
693 atr = at = __alloca (sizeof (struct gaih_addrtuple));
694 memset (at, '\0', sizeof (struct gaih_addrtuple));
40a55d20 695
7396d844
UD
696 if (req->ai_family == 0)
697 {
a0bf6ac7
UD
698 at->next = __alloca (sizeof (struct gaih_addrtuple));
699 memset (at->next, '\0', sizeof (struct gaih_addrtuple));
7396d844 700 }
40a55d20 701
7396d844
UD
702 if (req->ai_family == 0 || req->ai_family == AF_INET6)
703 {
704 at->family = AF_INET6;
705 if ((req->ai_flags & AI_PASSIVE) == 0)
a585ba22 706 memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
7396d844
UD
707 atr = at->next;
708 }
40a55d20 709
7396d844
UD
710 if (req->ai_family == 0 || req->ai_family == AF_INET)
711 {
712 atr->family = AF_INET;
713 if ((req->ai_flags & AI_PASSIVE) == 0)
714 *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
715 }
46ec036d 716 }
1fb05e3d 717
40a55d20
UD
718 if (pai == NULL)
719 return 0;
46ec036d
UD
720
721 {
722 const char *c = NULL;
723 struct gaih_servtuple *st2;
724 struct gaih_addrtuple *at2 = at;
40a55d20 725 size_t socklen, namelen;
85599e53 726 sa_family_t family;
40a55d20 727
f21acc89
UD
728 /*
729 buffer is the size of an unformatted IPv6 address in printable format.
730 */
40a55d20
UD
731 while (at2 != NULL)
732 {
733 if (req->ai_flags & AI_CANONNAME)
734 {
735 struct hostent *h = NULL;
46ec036d 736
40a55d20
UD
737 int herrno;
738 struct hostent th;
739 size_t tmpbuflen = 512;
2d37d6da 740 char *tmpbuf = NULL;
46ec036d 741
40a55d20
UD
742 do
743 {
2d37d6da 744 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2);
40a55d20
UD
745 rc = __gethostbyaddr_r (at2->addr,
746 ((at2->family == AF_INET6)
747 ? sizeof(struct in6_addr)
748 : sizeof(struct in_addr)),
749 at2->family, &th, tmpbuf, tmpbuflen,
750 &h, &herrno);
751
752 }
2d37d6da 753 while (rc == ERANGE && herrno == NETDB_INTERNAL);
40a55d20 754
a0bf6ac7 755 if (rc != 0 && herrno == NETDB_INTERNAL)
40a55d20
UD
756 {
757 __set_h_errno (herrno);
758 return -EAI_SYSTEM;
759 }
760
160d067b 761 if (h != NULL)
40a55d20 762 c = h->h_name;
160d067b
UD
763 else
764 {
765 /* We have to try to get the canonical in some other
766 way. If we are looking for either AF_INET or
767 AF_INET6 try the other line. */
768 if (req->ai_family == AF_UNSPEC)
769 {
770 struct addrinfo *p = NULL;
771 struct addrinfo **end = &p;
772 struct addrinfo localreq = *req;
773 struct addrinfo *runp;
774
775 localreq.ai_family = AF_INET + AF_INET6 - at2->family;
776 (void) gaih_inet (name, service, &localreq, end);
777
778 runp = p;
779 while (runp != NULL)
780 {
781 if (p->ai_canonname != name)
782 {
783 c = strdupa (p->ai_canonname);
784 break;
785 }
786 runp = runp->ai_next;
787 }
788
789 freeaddrinfo (p);
790 }
791
792 /* If this code is used the missing canonical name is
793 substituted with the name passed in by the user. */
794 if (c == NULL)
795 c = name;
796 }
40a55d20
UD
797
798 if (c == NULL)
799 return GAIH_OKIFUNSPEC | -EAI_NONAME;
800
801 namelen = strlen (c) + 1;
802 }
803 else
804 namelen = 0;
805
806 if (at2->family == AF_INET6)
85599e53
UD
807 {
808 family = AF_INET6;
809 socklen = sizeof (struct sockaddr_in6);
925c3c5c
UD
810
811 /* If we looked up IPv4 mapped address discard them here if
812 the caller isn't interested in all address and we have
813 found at least one IPv6 address. */
814 if (! got_ipv6
815 && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
816 && IN6_IS_ADDR_V4MAPPED (at2->addr))
817 goto ignore;
85599e53 818 }
40a55d20 819 else
85599e53
UD
820 {
821 family = AF_INET;
822 socklen = sizeof (struct sockaddr_in);
823 }
40a55d20
UD
824
825 for (st2 = st; st2 != NULL; st2 = st2->next)
826 {
827 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
828 if (*pai == NULL)
829 return -EAI_MEMORY;
830
831 (*pai)->ai_flags = req->ai_flags;
85599e53 832 (*pai)->ai_family = family;
40a55d20
UD
833 (*pai)->ai_socktype = st2->socktype;
834 (*pai)->ai_protocol = st2->protocol;
835 (*pai)->ai_addrlen = socklen;
925c3c5c 836 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
46ec036d 837#if SALEN
c0bc5f7b 838 (*pai)->ai_addr->sa_len = socklen;
46ec036d 839#endif /* SALEN */
85599e53 840 (*pai)->ai_addr->sa_family = family;
5a97622d 841
85599e53 842 if (family == AF_INET6)
40a55d20
UD
843 {
844 struct sockaddr_in6 *sin6p =
845 (struct sockaddr_in6 *) (*pai)->ai_addr;
46ec036d 846
40a55d20
UD
847 sin6p->sin6_flowinfo = 0;
848 memcpy (&sin6p->sin6_addr,
849 at2->addr, sizeof (struct in6_addr));
c0bc5f7b
UD
850 sin6p->sin6_port = st2->port;
851 sin6p->sin6_scope_id = at2->scopeid;
40a55d20
UD
852 }
853 else
854 {
855 struct sockaddr_in *sinp =
856 (struct sockaddr_in *) (*pai)->ai_addr;
857 memcpy (&sinp->sin_addr,
858 at2->addr, sizeof (struct in_addr));
c0bc5f7b 859 sinp->sin_port = st2->port;
40a55d20
UD
860 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
861 }
46ec036d 862
40a55d20
UD
863 if (c)
864 {
865 (*pai)->ai_canonname = ((void *) (*pai) +
866 sizeof (struct addrinfo) + socklen);
867 strcpy ((*pai)->ai_canonname, c);
868 }
869 else
870 (*pai)->ai_canonname = NULL;
46ec036d 871
40a55d20
UD
872 (*pai)->ai_next = NULL;
873 pai = &((*pai)->ai_next);
874 }
46ec036d 875
925c3c5c 876 ignore:
40a55d20
UD
877 at2 = at2->next;
878 }
46ec036d 879 }
40a55d20 880 return 0;
46ec036d
UD
881}
882
40a55d20
UD
883static struct gaih gaih[] =
884 {
885 { PF_INET6, gaih_inet },
886 { PF_INET, gaih_inet },
64b7897d 887#if 0
40a55d20 888 { PF_LOCAL, gaih_local },
64b7897d 889#endif
40a55d20
UD
890 { PF_UNSPEC, NULL }
891 };
46ec036d 892
40a55d20
UD
893int
894getaddrinfo (const char *name, const char *service,
895 const struct addrinfo *hints, struct addrinfo **pai)
46ec036d 896{
a0bf6ac7 897 int i = 0, j = 0, last_i = 0;
1fb05e3d 898 struct addrinfo *p = NULL, **end;
46ec036d
UD
899 struct gaih *g = gaih, *pg = NULL;
900 struct gaih_service gaih_service, *pservice;
925c3c5c 901 struct addrinfo local_hints;
46ec036d 902
40a55d20 903 if (name != NULL && name[0] == '*' && name[1] == 0)
1fb05e3d
UD
904 name = NULL;
905
40a55d20 906 if (service != NULL && service[0] == '*' && service[1] == 0)
1fb05e3d
UD
907 service = NULL;
908
40a55d20 909 if (name == NULL && service == NULL)
46ec036d
UD
910 return EAI_NONAME;
911
40a55d20
UD
912 if (hints == NULL)
913 hints = &default_hints;
46ec036d 914
925c3c5c
UD
915 if (hints->ai_flags
916 & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|AI_ADDRCONFIG|AI_V4MAPPED
917 |AI_ALL))
46ec036d
UD
918 return EAI_BADFLAGS;
919
40a55d20 920 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
46ec036d
UD
921 return EAI_BADFLAGS;
922
925c3c5c
UD
923 if (hints->ai_flags & AI_ADDRCONFIG)
924 {
925 /* Determine whether we have IPv4 or IPv6 interfaces or both.
926 We cannot cache the results since new interfaces could be
927 added at any time.
928
929 XXX We are using getifaddrs here which is more costly than
930 it is really necessary. Once things are stable we will have
931 a special function which performs the task with less overhead. */
932 struct ifaddrs* ifa = NULL;
933
934 if (getifaddrs (&ifa) != 0)
935 /* Cannot get the interface list, very bad. */
936 return EAI_SYSTEM;
937
938 bool seen_ipv4 = false;
939 bool seen_ipv6 = false;
940
941 while (ifa != NULL)
942 {
943 if (ifa->ifa_addr->sa_family == PF_INET)
944 seen_ipv4 = true;
945 else if (ifa->ifa_addr->sa_family == PF_INET6)
946 seen_ipv6 = true;
947
948 ifa = ifa->ifa_next;
949 }
950
951 (void) freeifaddrs (ifa);
952
953 /* Now make a decision on what we return, if anything. */
954 if (hints->ai_family == PF_UNSPEC)
955 {
956 /* If we haven't seen both IPv4 and IPv6 interfaces we can
957 narrow down the search. */
958 if (! seen_ipv4 || ! seen_ipv6)
959 {
960 local_hints = *hints;
961 local_hints.ai_family = seen_ipv4 ? PF_INET : PF_INET6;
962 hints = &local_hints;
963 }
964 }
965 else if ((hints->ai_family == PF_INET && ! seen_ipv4)
966 || (hints->ai_family == PF_INET6 && ! seen_ipv6))
967 /* We cannot possibly return a valid answer. */
968 return EAI_NONAME;
969 }
970
40a55d20
UD
971 if (service && service[0])
972 {
973 char *c;
974 gaih_service.name = service;
975 gaih_service.num = strtoul (gaih_service.name, &c, 10);
976 if (*c)
977 gaih_service.num = -1;
1fb05e3d 978 else
40a55d20
UD
979 /* Can't specify a numerical socket unless a protocol family was
980 given. */
85599e53 981 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
1fb05e3d 982 return EAI_SERVICE;
40a55d20
UD
983 pservice = &gaih_service;
984 }
985 else
46ec036d
UD
986 pservice = NULL;
987
1fb05e3d
UD
988 if (pai)
989 end = &p;
990 else
991 end = NULL;
992
40a55d20
UD
993 while (g->gaih)
994 {
7396d844 995 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
40a55d20
UD
996 {
997 j++;
7396d844 998 if (pg == NULL || pg->gaih != g->gaih)
40a55d20
UD
999 {
1000 pg = g;
7396d844
UD
1001 i = g->gaih (name, pservice, hints, end);
1002 if (i != 0)
40a55d20 1003 {
a0bf6ac7
UD
1004 /* EAI_NODATA is a more specific result as it says that
1005 we found a result but it is not usable. */
1006 if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA))
1007 last_i = i;
1008
7396d844 1009 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
160d067b
UD
1010 {
1011 ++g;
1012 continue;
1013 }
40a55d20 1014
160d067b 1015 freeaddrinfo (p);
40a55d20 1016
7396d844 1017 return -(i & GAIH_EAI);
40a55d20
UD
1018 }
1019 if (end)
1020 while(*end) end = &((*end)->ai_next);
1021 }
46ec036d 1022 }
40a55d20 1023 ++g;
46ec036d 1024 }
46ec036d 1025
40a55d20 1026 if (j == 0)
46ec036d
UD
1027 return EAI_FAMILY;
1028
40a55d20
UD
1029 if (p)
1030 {
1031 *pai = p;
1032 return 0;
1033 }
46ec036d 1034
a0bf6ac7 1035 if (pai == NULL && last_i == 0)
1fb05e3d
UD
1036 return 0;
1037
160d067b 1038 freeaddrinfo (p);
46ec036d 1039
a0bf6ac7 1040 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
46ec036d 1041}
9b0b40d3 1042libc_hidden_def (getaddrinfo)
46ec036d 1043
40a55d20
UD
1044void
1045freeaddrinfo (struct addrinfo *ai)
46ec036d
UD
1046{
1047 struct addrinfo *p;
1048
40a55d20
UD
1049 while (ai != NULL)
1050 {
1051 p = ai;
1052 ai = ai->ai_next;
1053 free (p);
1054 }
46ec036d 1055}
9b0b40d3 1056libc_hidden_def (freeaddrinfo)
This page took 0.364252 seconds and 5 git commands to generate.