2 * Copyright 1996 by Craig Metz
3 * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
5 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
8 /* $USAGI: getaddrinfo.c,v 1.16 2001/10/04 09:52:03 sekiya Exp $ */
10 /* The Inner Net License, Version 2.00
12 The author(s) grant permission for redistribution and use in source and
13 binary forms, with or without modification, of the software and documentation
14 provided that the following conditions are met:
16 0. If you receive a version of the software that is specifically labelled
17 as not being for redistribution (check the version message and/or README),
18 you are not permitted to redistribute that version of the software in any
20 1. All terms of the all other applicable copyrights and licenses must be
22 2. Redistributions of source code must retain the authors' copyright
23 notice(s), this list of conditions, and the following disclaimer.
24 3. Redistributions in binary form must reproduce the authors' copyright
25 notice(s), this list of conditions, and the following disclaimer in the
26 documentation and/or other materials provided with the distribution.
27 4. All advertising materials mentioning features or use of this software
28 must display the following acknowledgement with the name(s) of the
29 authors as specified in the copyright notice(s) substituted where
32 This product includes software developed by <name(s)>, The Inner
33 Net, and other contributors.
35 5. Neither the name(s) of the author(s) nor the names of its contributors
36 may be used to endorse or promote products derived from this software
37 without specific prior written permission.
39 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
40 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
41 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
42 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
43 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
44 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
46 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
48 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 If these license terms cause you a real problem, contact the author. */
62 #include <arpa/inet.h>
63 #include <sys/socket.h>
64 #include <netinet/in.h>
65 #include <sys/types.h>
67 #include <sys/utsname.h>
71 /* Experimentally off - libc_hidden_proto(memcpy) */
72 /* Experimentally off - libc_hidden_proto(memset) */
73 /* libc_hidden_proto(strcmp) */
74 /* libc_hidden_proto(stpcpy) */
75 /* Experimentally off - libc_hidden_proto(strchr) */
76 /* Experimentally off - libc_hidden_proto(strcpy) */
77 /* Experimentally off - libc_hidden_proto(strlen) */
78 libc_hidden_proto(socket)
79 libc_hidden_proto(close)
80 libc_hidden_proto(getservbyname_r)
81 libc_hidden_proto(gethostbyname_r)
82 libc_hidden_proto(gethostbyname2_r)
83 libc_hidden_proto(gethostbyaddr_r)
84 libc_hidden_proto(inet_pton)
85 libc_hidden_proto(inet_ntop)
86 libc_hidden_proto(strtoul)
87 libc_hidden_proto(if_nametoindex)
88 libc_hidden_proto(__h_errno_location)
89 /* libc_hidden_proto(uname) */
90 #ifdef __UCLIBC_HAS_IPV6__
91 libc_hidden_proto(in6addr_loopback)
94 #define GAIH_OKIFUNSPEC 0x0100
95 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
98 #define UNIX_PATH_MAX 108
107 struct gaih_servtuple
109 struct gaih_servtuple *next;
115 static const struct gaih_servtuple nullserv;
117 struct gaih_addrtuple
119 struct gaih_addrtuple *next;
125 struct gaih_typeproto
133 /* Values for `protoflag'. */
134 #define GAI_PROTO_NOSERVICE 1
135 #define GAI_PROTO_PROTOANY 2
137 static const struct gaih_typeproto gaih_inet_typeproto[] =
140 { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
141 { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
142 { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
149 int (*gaih)(const char *name, const struct gaih_service *service,
150 const struct addrinfo *req, struct addrinfo **pai);
154 static const struct addrinfo default_hints;
156 static const struct addrinfo default_hints =
157 { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
160 static int addrconfig (sa_family_t af)
164 int saved_errno = errno;
168 __check_pf(&seen_ipv4, &seen_ipv6);
170 ret = (int)seen_ipv4;
171 else if (af == AF_INET6)
172 ret = (int)seen_ipv6;
175 s = socket(af, SOCK_DGRAM, 0);
177 ret = (errno == EMFILE) ? 1 : 0;
184 __set_errno (saved_errno);
189 /* Using Unix sockets this way is a security risk. */
191 gaih_local (const char *name, const struct gaih_service *service,
192 const struct addrinfo *req, struct addrinfo **pai)
194 struct utsname utsname;
196 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
197 return GAIH_OKIFUNSPEC | -EAI_NONAME;
199 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
200 if (uname (&utsname) < 0)
205 if (strcmp(name, "localhost") &&
206 strcmp(name, "local") &&
207 strcmp(name, "unix") &&
208 strcmp(name, utsname.nodename))
209 return GAIH_OKIFUNSPEC | -EAI_NONAME;
212 if (req->ai_protocol || req->ai_socktype)
214 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
217 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
218 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
219 || (req->ai_protocol != 0
220 && !(tp->protoflag & GAI_PROTO_PROTOANY)
221 && req->ai_protocol != tp->protocol)))
226 if (req->ai_socktype)
227 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
229 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
233 *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
234 + ((req->ai_flags & AI_CANONNAME)
235 ? (strlen(utsname.nodename) + 1): 0));
239 (*pai)->ai_next = NULL;
240 (*pai)->ai_flags = req->ai_flags;
241 (*pai)->ai_family = AF_LOCAL;
242 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
243 (*pai)->ai_protocol = req->ai_protocol;
244 (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
245 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
248 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
249 sizeof (struct sockaddr_un);
252 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
253 memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
257 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
259 if (strchr (service->name, '/') != NULL)
261 if (strlen (service->name) >= sizeof (sunp->sun_path))
262 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
264 strcpy (sunp->sun_path, service->name);
268 if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
269 sizeof (sunp->sun_path))
270 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
272 stpcpy (stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
277 /* This is a dangerous use of the interface since there is a time
278 window between the test for the file and the actual creation
279 (done by the caller) in which a file with the same name could
281 char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
283 if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
285 || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
289 if (req->ai_flags & AI_CANONNAME)
290 (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
291 + sizeof (struct sockaddr_un),
294 (*pai)->ai_canonname = NULL;
300 gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
301 const struct addrinfo *req, struct gaih_servtuple *st)
304 size_t tmpbuflen = 1024;
311 tmpbuf = alloca (tmpbuflen);
313 r = getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
315 if (r != 0 || s == NULL)
320 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
326 st->socktype = tp->socktype;
327 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
328 ? req->ai_protocol : tp->protocol);
329 st->port = s->s_port;
334 #define gethosts(_family, _type) \
344 tmpbuf = alloca (tmpbuflen); \
345 rc = gethostbyname2_r (name, _family, &th, tmpbuf, \
346 tmpbuflen, &h, &herrno); \
347 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
350 if (herrno == NETDB_INTERNAL) \
352 __set_h_errno (herrno); \
353 return -EAI_SYSTEM; \
355 if (herrno == TRY_AGAIN) \
356 no_data = EAI_AGAIN; \
358 no_data = herrno == NO_DATA; \
360 else if (h != NULL) \
362 for (i = 0; h->h_addr_list[i]; i++) \
364 if (*pat == NULL) { \
365 *pat = alloca (sizeof(struct gaih_addrtuple)); \
366 (*pat)->scopeid = 0; \
368 (*pat)->next = NULL; \
369 (*pat)->family = _family; \
370 memcpy ((*pat)->addr, h->h_addr_list[i], \
372 pat = &((*pat)->next); \
378 gaih_inet (const char *name, const struct gaih_service *service,
379 const struct addrinfo *req, struct addrinfo **pai)
381 const struct gaih_typeproto *tp = gaih_inet_typeproto;
382 struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
383 struct gaih_addrtuple *at = NULL;
385 int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6) &&
386 (req->ai_flags & AI_V4MAPPED);
389 __check_pf(&seen_ipv4, &seen_ipv6);
391 if (req->ai_protocol || req->ai_socktype)
396 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
397 || (req->ai_protocol != 0
398 && !(tp->protoflag & GAI_PROTO_PROTOANY)
399 && req->ai_protocol != tp->protocol)))
404 if (req->ai_socktype)
405 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
407 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
413 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
414 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
416 if (service->num < 0)
420 st = (struct gaih_servtuple *)
421 alloca (sizeof (struct gaih_servtuple));
423 if ((rc = gaih_inet_serv (service->name, tp, req, st)))
428 struct gaih_servtuple **pst = &st;
429 for (tp++; tp->name[0]; tp++)
431 struct gaih_servtuple *newp;
433 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
436 if (req->ai_socktype != 0
437 && req->ai_socktype != tp->socktype)
439 if (req->ai_protocol != 0
440 && !(tp->protoflag & GAI_PROTO_PROTOANY)
441 && req->ai_protocol != tp->protocol)
444 newp = (struct gaih_servtuple *)
445 alloca (sizeof (struct gaih_servtuple));
447 if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
449 if (rc & GAIH_OKIFUNSPEC)
457 if (st == (struct gaih_servtuple *) &nullserv)
458 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
463 st = alloca (sizeof (struct gaih_servtuple));
465 st->socktype = tp->socktype;
466 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
467 ? req->ai_protocol : tp->protocol);
468 st->port = htons (service->num);
471 else if (req->ai_socktype || req->ai_protocol)
473 st = alloca (sizeof (struct gaih_servtuple));
475 st->socktype = tp->socktype;
476 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
477 ? req->ai_protocol : tp->protocol);
483 * Neither socket type nor protocol is set. Return all socket types
486 struct gaih_servtuple **lastp = &st;
487 for (++tp; tp->name[0]; ++tp)
489 struct gaih_servtuple *newp;
491 newp = alloca (sizeof (struct gaih_servtuple));
493 newp->socktype = tp->socktype;
494 newp->protocol = tp->protocol;
504 at = alloca (sizeof (struct gaih_addrtuple));
506 at->family = AF_UNSPEC;
510 if (inet_pton (AF_INET, name, at->addr) > 0)
512 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
513 at->family = AF_INET;
518 #if defined __UCLIBC_HAS_IPV6__
519 if (at->family == AF_UNSPEC)
521 char *namebuf = strdupa (name);
524 scope_delim = strchr (namebuf, SCOPE_DELIMITER);
525 if (scope_delim != NULL)
528 if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
530 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
531 at->family = AF_INET6;
535 if (scope_delim != NULL)
537 int try_numericscope = 0;
538 if (IN6_IS_ADDR_LINKLOCAL (at->addr)
539 || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
541 at->scopeid = if_nametoindex (scope_delim + 1);
542 if (at->scopeid == 0)
543 try_numericscope = 1;
546 try_numericscope = 1;
548 if (try_numericscope != 0)
551 assert (sizeof (uint32_t) <= sizeof (unsigned long));
552 at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
555 return GAIH_OKIFUNSPEC | -EAI_NONAME;
562 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
565 struct gaih_addrtuple **pat = &at;
570 * If we are looking for both IPv4 and IPv6 address we don't want
571 * the lookup functions to automatically promote IPv4 addresses to
575 #if defined __UCLIBC_HAS_IPV6__
576 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
577 if (!(req->ai_flags & AI_ADDRCONFIG) || seen_ipv6)
578 gethosts (AF_INET6, struct in6_addr);
580 no_inet6_data = no_data;
582 if (req->ai_family == AF_INET ||
583 (!v4mapped && req->ai_family == AF_UNSPEC) ||
584 (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL))))
585 if (!(req->ai_flags & AI_ADDRCONFIG) || seen_ipv4)
586 gethosts (AF_INET, struct in_addr);
588 if (no_data != 0 && no_inet6_data != 0)
590 /* If both requests timed out report this. */
591 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
595 * We made requests but they turned out no data.
596 * The name is known, though.
598 return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
602 if (at->family == AF_UNSPEC)
603 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
607 struct gaih_addrtuple *atr;
608 atr = at = alloca (sizeof (struct gaih_addrtuple));
609 memset (at, '\0', sizeof (struct gaih_addrtuple));
611 if (req->ai_family == 0)
613 at->next = alloca (sizeof (struct gaih_addrtuple));
614 memset (at->next, '\0', sizeof (struct gaih_addrtuple));
617 #if defined __UCLIBC_HAS_IPV6__
618 if (req->ai_family == 0 || req->ai_family == AF_INET6)
620 at->family = AF_INET6;
621 if ((req->ai_flags & AI_PASSIVE) == 0)
622 memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
627 if (req->ai_family == 0 || req->ai_family == AF_INET)
629 atr->family = AF_INET;
630 if ((req->ai_flags & AI_PASSIVE) == 0)
631 *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
639 const char *c = NULL;
640 struct gaih_servtuple *st2;
641 struct gaih_addrtuple *at2 = at;
642 size_t socklen, namelen;
646 * buffer is the size of an unformatted IPv6 address in
649 char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
653 if (req->ai_flags & AI_CANONNAME)
655 struct hostent *h = NULL;
659 size_t tmpbuflen = 512;
665 tmpbuf = alloca (tmpbuflen);
670 rc = gethostbyaddr_r (at2->addr,
671 ((at2->family == AF_INET6)
672 ? sizeof(struct in6_addr)
673 : sizeof(struct in_addr)),
674 at2->family, &th, tmpbuf, tmpbuflen,
678 while (rc == errno && herrno == NETDB_INTERNAL);
680 if (rc != 0 && herrno == NETDB_INTERNAL)
682 __set_h_errno (herrno);
687 c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
692 return GAIH_OKIFUNSPEC | -EAI_NONAME;
694 namelen = strlen (c) + 1;
699 #if defined __UCLIBC_HAS_IPV6__
700 if (at2->family == AF_INET6 || v4mapped)
703 socklen = sizeof (struct sockaddr_in6);
706 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
709 #if defined __UCLIBC_HAS_IPV4__
712 socklen = sizeof (struct sockaddr_in);
715 for (st2 = st; st2 != NULL; st2 = st2->next)
717 if (req->ai_flags & AI_ADDRCONFIG) {
718 if (family == AF_INET && !seen_ipv4)
720 #if defined __UCLIBC_HAS_IPV6__
721 else if (family == AF_INET6 && !seen_ipv6)
725 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
729 (*pai)->ai_flags = req->ai_flags;
730 (*pai)->ai_family = family;
731 (*pai)->ai_socktype = st2->socktype;
732 (*pai)->ai_protocol = st2->protocol;
733 (*pai)->ai_addrlen = socklen;
734 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
736 (*pai)->ai_addr->sa_len = socklen;
738 (*pai)->ai_addr->sa_family = family;
740 #if defined __UCLIBC_HAS_IPV6__
741 if (family == AF_INET6)
743 struct sockaddr_in6 *sin6p =
744 (struct sockaddr_in6 *) (*pai)->ai_addr;
746 sin6p->sin6_flowinfo = 0;
747 if (at2->family == AF_INET6)
749 memcpy (&sin6p->sin6_addr,
750 at2->addr, sizeof (struct in6_addr));
754 sin6p->sin6_addr.s6_addr32[0] = 0;
755 sin6p->sin6_addr.s6_addr32[1] = 0;
756 sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
757 memcpy(&sin6p->sin6_addr.s6_addr32[3],
758 at2->addr, sizeof (sin6p->sin6_addr.s6_addr32[3]));
760 sin6p->sin6_port = st2->port;
761 sin6p->sin6_scope_id = at2->scopeid;
764 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
767 #if defined __UCLIBC_HAS_IPV4__
769 struct sockaddr_in *sinp =
770 (struct sockaddr_in *) (*pai)->ai_addr;
772 memcpy (&sinp->sin_addr,
773 at2->addr, sizeof (struct in_addr));
774 sinp->sin_port = st2->port;
775 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
780 (*pai)->ai_canonname = ((void *) (*pai) +
781 sizeof (struct addrinfo) + socklen);
782 strcpy ((*pai)->ai_canonname, c);
785 (*pai)->ai_canonname = NULL;
787 (*pai)->ai_next = NULL;
788 pai = &((*pai)->ai_next);
797 static struct gaih gaih[] =
799 #if defined __UCLIBC_HAS_IPV6__
800 { PF_INET6, gaih_inet },
802 { PF_INET, gaih_inet },
804 { PF_LOCAL, gaih_local },
809 libc_hidden_proto(freeaddrinfo)
811 freeaddrinfo (struct addrinfo *ai)
822 libc_hidden_def(freeaddrinfo)
824 libc_hidden_proto(getaddrinfo)
826 getaddrinfo (const char *name, const char *service,
827 const struct addrinfo *hints, struct addrinfo **pai)
829 int i = 0, j = 0, last_i = 0;
830 struct addrinfo *p = NULL, **end;
831 struct gaih *g = gaih, *pg = NULL;
832 struct gaih_service gaih_service, *pservice;
834 if (name != NULL && name[0] == '*' && name[1] == 0)
837 if (service != NULL && service[0] == '*' && service[1] == 0)
840 if (name == NULL && service == NULL)
844 hints = &default_hints;
846 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
847 AI_ADDRCONFIG|AI_V4MAPPED|AI_NUMERICSERV|AI_ALL))
850 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
853 if (service && service[0])
856 gaih_service.name = service;
857 gaih_service.num = strtoul (gaih_service.name, &c, 10);
859 if (hints->ai_flags & AI_NUMERICSERV)
862 gaih_service.num = -1;
866 * Can't specify a numerical socket unless a protocol
869 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
871 pservice = &gaih_service;
883 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
885 if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family))
891 if (pg == NULL || pg->gaih != g->gaih)
894 i = g->gaih (name, pservice, hints, end);
899 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
905 return -(i & GAIH_EAI);
908 while(*end) end = &((*end)->ai_next);
923 if (pai == NULL && last_i == 0)
929 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
931 libc_hidden_def(getaddrinfo)