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>
70 /* Experimentally off - libc_hidden_proto(memcpy) */
71 /* Experimentally off - libc_hidden_proto(memset) */
72 /* libc_hidden_proto(strcmp) */
73 /* libc_hidden_proto(stpcpy) */
74 /* Experimentally off - libc_hidden_proto(strchr) */
75 /* Experimentally off - libc_hidden_proto(strcpy) */
76 /* Experimentally off - libc_hidden_proto(strlen) */
77 libc_hidden_proto(socket)
78 libc_hidden_proto(close)
79 libc_hidden_proto(getservbyname_r)
80 libc_hidden_proto(gethostbyname_r)
81 libc_hidden_proto(gethostbyname2_r)
82 libc_hidden_proto(gethostbyaddr_r)
83 libc_hidden_proto(inet_pton)
84 libc_hidden_proto(inet_ntop)
85 libc_hidden_proto(strtoul)
86 libc_hidden_proto(if_nametoindex)
87 libc_hidden_proto(__h_errno_location)
88 /* libc_hidden_proto(uname) */
89 #ifdef __UCLIBC_HAS_IPV6__
90 libc_hidden_proto(in6addr_loopback)
93 #define GAIH_OKIFUNSPEC 0x0100
94 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
97 #define UNIX_PATH_MAX 108
106 struct gaih_servtuple
108 struct gaih_servtuple *next;
114 static const struct gaih_servtuple nullserv;
116 struct gaih_addrtuple
118 struct gaih_addrtuple *next;
124 struct gaih_typeproto
132 /* Values for `protoflag'. */
133 #define GAI_PROTO_NOSERVICE 1
134 #define GAI_PROTO_PROTOANY 2
136 static const struct gaih_typeproto gaih_inet_typeproto[] =
139 { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
140 { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
141 { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
148 int (*gaih)(const char *name, const struct gaih_service *service,
149 const struct addrinfo *req, struct addrinfo **pai);
153 static const struct addrinfo default_hints;
155 static const struct addrinfo default_hints =
156 { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
160 static int addrconfig (sa_family_t af)
164 int saved_errno = errno;
165 s = socket(af, SOCK_DGRAM, 0);
167 ret = (errno == EMFILE) ? 1 : 0;
173 __set_errno (saved_errno);
178 /* Using Unix sockets this way is a security risk. */
180 gaih_local (const char *name, const struct gaih_service *service,
181 const struct addrinfo *req, struct addrinfo **pai)
183 struct utsname utsname;
185 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
186 return GAIH_OKIFUNSPEC | -EAI_NONAME;
188 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
189 if (uname (&utsname) < 0)
194 if (strcmp(name, "localhost") &&
195 strcmp(name, "local") &&
196 strcmp(name, "unix") &&
197 strcmp(name, utsname.nodename))
198 return GAIH_OKIFUNSPEC | -EAI_NONAME;
201 if (req->ai_protocol || req->ai_socktype)
203 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
206 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
207 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
208 || (req->ai_protocol != 0
209 && !(tp->protoflag & GAI_PROTO_PROTOANY)
210 && req->ai_protocol != tp->protocol)))
215 if (req->ai_socktype)
216 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
218 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
222 *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
223 + ((req->ai_flags & AI_CANONNAME)
224 ? (strlen(utsname.nodename) + 1): 0));
228 (*pai)->ai_next = NULL;
229 (*pai)->ai_flags = req->ai_flags;
230 (*pai)->ai_family = AF_LOCAL;
231 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
232 (*pai)->ai_protocol = req->ai_protocol;
233 (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
234 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
237 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
238 sizeof (struct sockaddr_un);
241 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
242 memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
246 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
248 if (strchr (service->name, '/') != NULL)
250 if (strlen (service->name) >= sizeof (sunp->sun_path))
251 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
253 strcpy (sunp->sun_path, service->name);
257 if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
258 sizeof (sunp->sun_path))
259 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
261 stpcpy (stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
266 /* This is a dangerous use of the interface since there is a time
267 window between the test for the file and the actual creation
268 (done by the caller) in which a file with the same name could
270 char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
272 if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
274 || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
278 if (req->ai_flags & AI_CANONNAME)
279 (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
280 + sizeof (struct sockaddr_un),
283 (*pai)->ai_canonname = NULL;
289 gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
290 const struct addrinfo *req, struct gaih_servtuple *st)
293 size_t tmpbuflen = 1024;
300 tmpbuf = alloca (tmpbuflen);
302 r = getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
304 if (r != 0 || s == NULL)
309 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
315 st->socktype = tp->socktype;
316 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
317 ? req->ai_protocol : tp->protocol);
318 st->port = s->s_port;
323 #define gethosts(_family, _type) \
333 tmpbuf = alloca (tmpbuflen); \
334 rc = gethostbyname2_r (name, _family, &th, tmpbuf, \
335 tmpbuflen, &h, &herrno); \
336 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
339 if (herrno == NETDB_INTERNAL) \
341 __set_h_errno (herrno); \
342 return -EAI_SYSTEM; \
344 if (herrno == TRY_AGAIN) \
345 no_data = EAI_AGAIN; \
347 no_data = herrno == NO_DATA; \
349 else if (h != NULL) \
351 for (i = 0; h->h_addr_list[i]; i++) \
353 if (*pat == NULL) { \
354 *pat = alloca (sizeof(struct gaih_addrtuple)); \
355 (*pat)->scopeid = 0; \
357 (*pat)->next = NULL; \
358 (*pat)->family = _family; \
359 memcpy ((*pat)->addr, h->h_addr_list[i], \
361 pat = &((*pat)->next); \
367 gaih_inet (const char *name, const struct gaih_service *service,
368 const struct addrinfo *req, struct addrinfo **pai)
370 const struct gaih_typeproto *tp = gaih_inet_typeproto;
371 struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
372 struct gaih_addrtuple *at = NULL;
374 int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6) &&
375 (req->ai_flags & AI_V4MAPPED);
377 if (req->ai_protocol || req->ai_socktype)
382 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
383 || (req->ai_protocol != 0
384 && !(tp->protoflag & GAI_PROTO_PROTOANY)
385 && req->ai_protocol != tp->protocol)))
390 if (req->ai_socktype)
391 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
393 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
399 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
400 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
402 if (service->num < 0)
406 st = (struct gaih_servtuple *)
407 alloca (sizeof (struct gaih_servtuple));
409 if ((rc = gaih_inet_serv (service->name, tp, req, st)))
414 struct gaih_servtuple **pst = &st;
415 for (tp++; tp->name[0]; tp++)
417 struct gaih_servtuple *newp;
419 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
422 if (req->ai_socktype != 0
423 && req->ai_socktype != tp->socktype)
425 if (req->ai_protocol != 0
426 && !(tp->protoflag & GAI_PROTO_PROTOANY)
427 && req->ai_protocol != tp->protocol)
430 newp = (struct gaih_servtuple *)
431 alloca (sizeof (struct gaih_servtuple));
433 if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
435 if (rc & GAIH_OKIFUNSPEC)
443 if (st == (struct gaih_servtuple *) &nullserv)
444 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
449 st = alloca (sizeof (struct gaih_servtuple));
451 st->socktype = tp->socktype;
452 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
453 ? req->ai_protocol : tp->protocol);
454 st->port = htons (service->num);
457 else if (req->ai_socktype || req->ai_protocol)
459 st = alloca (sizeof (struct gaih_servtuple));
461 st->socktype = tp->socktype;
462 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
463 ? req->ai_protocol : tp->protocol);
469 * Neither socket type nor protocol is set. Return all socket types
472 struct gaih_servtuple **lastp = &st;
473 for (++tp; tp->name[0]; ++tp)
475 struct gaih_servtuple *newp;
477 newp = alloca (sizeof (struct gaih_servtuple));
479 newp->socktype = tp->socktype;
480 newp->protocol = tp->protocol;
490 at = alloca (sizeof (struct gaih_addrtuple));
492 at->family = AF_UNSPEC;
496 if (inet_pton (AF_INET, name, at->addr) > 0)
498 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
499 at->family = AF_INET;
504 #if defined __UCLIBC_HAS_IPV6__
505 if (at->family == AF_UNSPEC)
507 char *namebuf = strdupa (name);
510 scope_delim = strchr (namebuf, SCOPE_DELIMITER);
511 if (scope_delim != NULL)
514 if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
516 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
517 at->family = AF_INET6;
521 if (scope_delim != NULL)
523 int try_numericscope = 0;
524 if (IN6_IS_ADDR_LINKLOCAL (at->addr)
525 || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
527 at->scopeid = if_nametoindex (scope_delim + 1);
528 if (at->scopeid == 0)
529 try_numericscope = 1;
532 try_numericscope = 1;
534 if (try_numericscope != 0)
537 assert (sizeof (uint32_t) <= sizeof (unsigned long));
538 at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
541 return GAIH_OKIFUNSPEC | -EAI_NONAME;
548 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
551 struct gaih_addrtuple **pat = &at;
556 * If we are looking for both IPv4 and IPv6 address we don't want
557 * the lookup functions to automatically promote IPv4 addresses to
561 #if defined __UCLIBC_HAS_IPV6__
562 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
563 gethosts (AF_INET6, struct in6_addr);
565 no_inet6_data = no_data;
567 if (req->ai_family == AF_INET ||
568 (!v4mapped && req->ai_family == AF_UNSPEC) ||
569 (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL))))
570 gethosts (AF_INET, struct in_addr);
572 if (no_data != 0 && no_inet6_data != 0)
574 /* If both requests timed out report this. */
575 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
579 * We made requests but they turned out no data.
580 * The name is known, though.
582 return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
586 if (at->family == AF_UNSPEC)
587 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
591 struct gaih_addrtuple *atr;
592 atr = at = alloca (sizeof (struct gaih_addrtuple));
593 memset (at, '\0', sizeof (struct gaih_addrtuple));
595 if (req->ai_family == 0)
597 at->next = alloca (sizeof (struct gaih_addrtuple));
598 memset (at->next, '\0', sizeof (struct gaih_addrtuple));
601 #if defined __UCLIBC_HAS_IPV6__
602 if (req->ai_family == 0 || req->ai_family == AF_INET6)
604 at->family = AF_INET6;
605 if ((req->ai_flags & AI_PASSIVE) == 0)
606 memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
611 if (req->ai_family == 0 || req->ai_family == AF_INET)
613 atr->family = AF_INET;
614 if ((req->ai_flags & AI_PASSIVE) == 0)
615 *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
623 const char *c = NULL;
624 struct gaih_servtuple *st2;
625 struct gaih_addrtuple *at2 = at;
626 size_t socklen, namelen;
630 * buffer is the size of an unformatted IPv6 address in
633 char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
637 if (req->ai_flags & AI_CANONNAME)
639 struct hostent *h = NULL;
643 size_t tmpbuflen = 512;
649 tmpbuf = alloca (tmpbuflen);
654 rc = gethostbyaddr_r (at2->addr,
655 ((at2->family == AF_INET6)
656 ? sizeof(struct in6_addr)
657 : sizeof(struct in_addr)),
658 at2->family, &th, tmpbuf, tmpbuflen,
662 while (rc == errno && herrno == NETDB_INTERNAL);
664 if (rc != 0 && herrno == NETDB_INTERNAL)
666 __set_h_errno (herrno);
671 c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
676 return GAIH_OKIFUNSPEC | -EAI_NONAME;
678 namelen = strlen (c) + 1;
683 #if defined __UCLIBC_HAS_IPV6__
684 if (at2->family == AF_INET6 || v4mapped)
687 socklen = sizeof (struct sockaddr_in6);
690 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
693 #if defined __UCLIBC_HAS_IPV4__
696 socklen = sizeof (struct sockaddr_in);
699 for (st2 = st; st2 != NULL; st2 = st2->next)
701 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
705 (*pai)->ai_flags = req->ai_flags;
706 (*pai)->ai_family = family;
707 (*pai)->ai_socktype = st2->socktype;
708 (*pai)->ai_protocol = st2->protocol;
709 (*pai)->ai_addrlen = socklen;
710 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
712 (*pai)->ai_addr->sa_len = socklen;
714 (*pai)->ai_addr->sa_family = family;
716 #if defined __UCLIBC_HAS_IPV6__
717 if (family == AF_INET6)
719 struct sockaddr_in6 *sin6p =
720 (struct sockaddr_in6 *) (*pai)->ai_addr;
722 sin6p->sin6_flowinfo = 0;
723 if (at2->family == AF_INET6)
725 memcpy (&sin6p->sin6_addr,
726 at2->addr, sizeof (struct in6_addr));
730 sin6p->sin6_addr.s6_addr32[0] = 0;
731 sin6p->sin6_addr.s6_addr32[1] = 0;
732 sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
733 memcpy(&sin6p->sin6_addr.s6_addr32[3],
734 at2->addr, sizeof (sin6p->sin6_addr.s6_addr32[3]));
736 sin6p->sin6_port = st2->port;
737 sin6p->sin6_scope_id = at2->scopeid;
740 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
743 #if defined __UCLIBC_HAS_IPV4__
745 struct sockaddr_in *sinp =
746 (struct sockaddr_in *) (*pai)->ai_addr;
748 memcpy (&sinp->sin_addr,
749 at2->addr, sizeof (struct in_addr));
750 sinp->sin_port = st2->port;
751 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
756 (*pai)->ai_canonname = ((void *) (*pai) +
757 sizeof (struct addrinfo) + socklen);
758 strcpy ((*pai)->ai_canonname, c);
761 (*pai)->ai_canonname = NULL;
763 (*pai)->ai_next = NULL;
764 pai = &((*pai)->ai_next);
773 static struct gaih gaih[] =
775 #if defined __UCLIBC_HAS_IPV6__
776 { PF_INET6, gaih_inet },
778 { PF_INET, gaih_inet },
780 { PF_LOCAL, gaih_local },
785 libc_hidden_proto(freeaddrinfo)
787 freeaddrinfo (struct addrinfo *ai)
798 libc_hidden_def(freeaddrinfo)
800 libc_hidden_proto(getaddrinfo)
802 getaddrinfo (const char *name, const char *service,
803 const struct addrinfo *hints, struct addrinfo **pai)
805 int i = 0, j = 0, last_i = 0;
806 struct addrinfo *p = NULL, **end;
807 struct gaih *g = gaih, *pg = NULL;
808 struct gaih_service gaih_service, *pservice;
810 if (name != NULL && name[0] == '*' && name[1] == 0)
813 if (service != NULL && service[0] == '*' && service[1] == 0)
816 if (name == NULL && service == NULL)
820 hints = &default_hints;
822 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
823 AI_ADDRCONFIG|AI_V4MAPPED|AI_NUMERICSERV|AI_ALL))
826 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
829 if (service && service[0])
832 gaih_service.name = service;
833 gaih_service.num = strtoul (gaih_service.name, &c, 10);
835 if (hints->ai_flags & AI_NUMERICSERV)
838 gaih_service.num = -1;
842 * Can't specify a numerical socket unless a protocol
845 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
847 pservice = &gaih_service;
859 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
861 if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family))
864 if (pg == NULL || pg->gaih != g->gaih)
867 i = g->gaih (name, pservice, hints, end);
872 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
878 return -(i & GAIH_EAI);
881 while(*end) end = &((*end)->ai_next);
896 if (pai == NULL && last_i == 0)
902 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
904 libc_hidden_def(getaddrinfo)