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. */
63 #include <arpa/inet.h>
64 #include <sys/socket.h>
65 #include <netinet/in.h>
66 #include <sys/types.h>
68 #include <sys/utsname.h>
71 libc_hidden_proto(memcpy)
72 libc_hidden_proto(memset)
73 /* libc_hidden_proto(strcmp) */
74 /* libc_hidden_proto(stpcpy) */
75 libc_hidden_proto(strchr)
76 libc_hidden_proto(strcpy)
77 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(uname) */
89 #ifdef __UCLIBC_HAS_IPV6__
90 libc_hidden_proto(in6addr_loopback)
93 /* The following declarations and definitions have been removed from
94 * the public header since we don't want people to use them. */
95 #define AI_V4MAPPED 0x0008 /* IPv4-mapped addresses are acceptable. */
96 #define AI_ALL 0x0010 /* Return both IPv4 and IPv6 addresses. */
97 #define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose
98 returned address type. */
99 #define AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG)
102 #define GAIH_OKIFUNSPEC 0x0100
103 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
105 #ifndef UNIX_PATH_MAX
106 #define UNIX_PATH_MAX 108
115 struct gaih_servtuple
117 struct gaih_servtuple *next;
123 static const struct gaih_servtuple nullserv;
125 struct gaih_addrtuple
127 struct gaih_addrtuple *next;
133 struct gaih_typeproto
141 /* Values for `protoflag'. */
142 #define GAI_PROTO_NOSERVICE 1
143 #define GAI_PROTO_PROTOANY 2
145 static const struct gaih_typeproto gaih_inet_typeproto[] =
148 { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
149 { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
150 { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
157 int (*gaih)(const char *name, const struct gaih_service *service,
158 const struct addrinfo *req, struct addrinfo **pai);
162 static const struct addrinfo default_hints;
164 static const struct addrinfo default_hints =
165 { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
169 static int addrconfig (sa_family_t af)
173 int saved_errno = errno;
174 s = socket(af, SOCK_DGRAM, 0);
176 ret = (errno == EMFILE) ? 1 : 0;
182 __set_errno (saved_errno);
187 /* Using Unix sockets this way is a security risk. */
189 gaih_local (const char *name, const struct gaih_service *service,
190 const struct addrinfo *req, struct addrinfo **pai)
192 struct utsname utsname;
194 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
195 return GAIH_OKIFUNSPEC | -EAI_NONAME;
197 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
198 if (uname (&utsname) < 0)
203 if (strcmp(name, "localhost") &&
204 strcmp(name, "local") &&
205 strcmp(name, "unix") &&
206 strcmp(name, utsname.nodename))
207 return GAIH_OKIFUNSPEC | -EAI_NONAME;
210 if (req->ai_protocol || req->ai_socktype)
212 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
215 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
216 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
217 || (req->ai_protocol != 0
218 && !(tp->protoflag & GAI_PROTO_PROTOANY)
219 && req->ai_protocol != tp->protocol)))
224 if (req->ai_socktype)
225 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
227 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
231 *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
232 + ((req->ai_flags & AI_CANONNAME)
233 ? (strlen(utsname.nodename) + 1): 0));
237 (*pai)->ai_next = NULL;
238 (*pai)->ai_flags = req->ai_flags;
239 (*pai)->ai_family = AF_LOCAL;
240 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
241 (*pai)->ai_protocol = req->ai_protocol;
242 (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
243 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
246 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
247 sizeof (struct sockaddr_un);
250 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
251 memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
255 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
257 if (strchr (service->name, '/') != NULL)
259 if (strlen (service->name) >= sizeof (sunp->sun_path))
260 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
262 strcpy (sunp->sun_path, service->name);
266 if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
267 sizeof (sunp->sun_path))
268 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
270 stpcpy (stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
275 /* This is a dangerous use of the interface since there is a time
276 window between the test for the file and the actual creation
277 (done by the caller) in which a file with the same name could
279 char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
281 if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
283 || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
287 if (req->ai_flags & AI_CANONNAME)
288 (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
289 + sizeof (struct sockaddr_un),
292 (*pai)->ai_canonname = NULL;
298 gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
299 const struct addrinfo *req, struct gaih_servtuple *st)
302 size_t tmpbuflen = 1024;
309 tmpbuf = alloca (tmpbuflen);
311 r = getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
313 if (r != 0 || s == NULL)
318 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
324 st->socktype = tp->socktype;
325 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
326 ? req->ai_protocol : tp->protocol);
327 st->port = s->s_port;
332 #define gethosts(_family, _type) \
342 tmpbuf = alloca (tmpbuflen); \
343 rc = gethostbyname2_r (name, _family, &th, tmpbuf, \
344 tmpbuflen, &h, &herrno); \
345 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
348 if (herrno == NETDB_INTERNAL) \
350 __set_h_errno (herrno); \
351 return -EAI_SYSTEM; \
353 if (herrno == TRY_AGAIN) \
354 no_data = EAI_AGAIN; \
356 no_data = herrno == NO_DATA; \
358 else if (h != NULL) \
360 for (i = 0; h->h_addr_list[i]; i++) \
362 if (*pat == NULL) { \
363 *pat = alloca (sizeof(struct gaih_addrtuple)); \
364 (*pat)->scopeid = 0; \
366 (*pat)->next = NULL; \
367 (*pat)->family = _family; \
368 memcpy ((*pat)->addr, h->h_addr_list[i], \
370 pat = &((*pat)->next); \
376 gaih_inet (const char *name, const struct gaih_service *service,
377 const struct addrinfo *req, struct addrinfo **pai)
379 const struct gaih_typeproto *tp = gaih_inet_typeproto;
380 struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
381 struct gaih_addrtuple *at = NULL;
383 int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6) &&
384 (req->ai_flags & AI_V4MAPPED);
386 if (req->ai_protocol || req->ai_socktype)
391 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
392 || (req->ai_protocol != 0
393 && !(tp->protoflag & GAI_PROTO_PROTOANY)
394 && req->ai_protocol != tp->protocol)))
399 if (req->ai_socktype)
400 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
402 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
408 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
409 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
411 if (service->num < 0)
415 st = (struct gaih_servtuple *)
416 alloca (sizeof (struct gaih_servtuple));
418 if ((rc = gaih_inet_serv (service->name, tp, req, st)))
423 struct gaih_servtuple **pst = &st;
424 for (tp++; tp->name[0]; tp++)
426 struct gaih_servtuple *newp;
428 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
431 if (req->ai_socktype != 0
432 && req->ai_socktype != tp->socktype)
434 if (req->ai_protocol != 0
435 && !(tp->protoflag & GAI_PROTO_PROTOANY)
436 && req->ai_protocol != tp->protocol)
439 newp = (struct gaih_servtuple *)
440 alloca (sizeof (struct gaih_servtuple));
442 if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
444 if (rc & GAIH_OKIFUNSPEC)
452 if (st == (struct gaih_servtuple *) &nullserv)
453 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
458 st = alloca (sizeof (struct gaih_servtuple));
460 st->socktype = tp->socktype;
461 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
462 ? req->ai_protocol : tp->protocol);
463 st->port = htons (service->num);
466 else if (req->ai_socktype || req->ai_protocol)
468 st = alloca (sizeof (struct gaih_servtuple));
470 st->socktype = tp->socktype;
471 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
472 ? req->ai_protocol : tp->protocol);
478 * Neither socket type nor protocol is set. Return all socket types
481 struct gaih_servtuple **lastp = &st;
482 for (++tp; tp->name[0]; ++tp)
484 struct gaih_servtuple *newp;
486 newp = alloca (sizeof (struct gaih_servtuple));
488 newp->socktype = tp->socktype;
489 newp->protocol = tp->protocol;
499 at = alloca (sizeof (struct gaih_addrtuple));
501 at->family = AF_UNSPEC;
505 if (inet_pton (AF_INET, name, at->addr) > 0)
507 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
508 at->family = AF_INET;
513 #if __UCLIBC_HAS_IPV6__
514 if (at->family == AF_UNSPEC)
516 char *namebuf = strdupa (name);
519 scope_delim = strchr (namebuf, SCOPE_DELIMITER);
520 if (scope_delim != NULL)
523 if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
525 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
526 at->family = AF_INET6;
530 if (scope_delim != NULL)
532 int try_numericscope = 0;
533 if (IN6_IS_ADDR_LINKLOCAL (at->addr)
534 || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
536 at->scopeid = if_nametoindex (scope_delim + 1);
537 if (at->scopeid == 0)
538 try_numericscope = 1;
541 try_numericscope = 1;
543 if (try_numericscope != 0)
546 assert (sizeof (uint32_t) <= sizeof (unsigned long));
547 at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
550 return GAIH_OKIFUNSPEC | -EAI_NONAME;
557 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
560 struct gaih_addrtuple **pat = &at;
565 * If we are looking for both IPv4 and IPv6 address we don't want
566 * the lookup functions to automatically promote IPv4 addresses to
570 #if __UCLIBC_HAS_IPV6__
571 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
572 gethosts (AF_INET6, struct in6_addr);
574 no_inet6_data = no_data;
576 if (req->ai_family == AF_INET ||
577 (!v4mapped && req->ai_family == AF_UNSPEC) ||
578 (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL))))
579 gethosts (AF_INET, struct in_addr);
581 if (no_data != 0 && no_inet6_data != 0)
583 /* If both requests timed out report this. */
584 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
588 * We made requests but they turned out no data.
589 * The name is known, though.
591 return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
595 if (at->family == AF_UNSPEC)
596 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
600 struct gaih_addrtuple *atr;
601 atr = at = alloca (sizeof (struct gaih_addrtuple));
602 memset (at, '\0', sizeof (struct gaih_addrtuple));
604 if (req->ai_family == 0)
606 at->next = alloca (sizeof (struct gaih_addrtuple));
607 memset (at->next, '\0', sizeof (struct gaih_addrtuple));
610 #if __UCLIBC_HAS_IPV6__
611 if (req->ai_family == 0 || req->ai_family == AF_INET6)
613 at->family = AF_INET6;
614 if ((req->ai_flags & AI_PASSIVE) == 0)
615 memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
620 if (req->ai_family == 0 || req->ai_family == AF_INET)
622 atr->family = AF_INET;
623 if ((req->ai_flags & AI_PASSIVE) == 0)
624 *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
632 const char *c = NULL;
633 struct gaih_servtuple *st2;
634 struct gaih_addrtuple *at2 = at;
635 size_t socklen, namelen;
639 * buffer is the size of an unformatted IPv6 address in
642 char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
646 if (req->ai_flags & AI_CANONNAME)
648 struct hostent *h = NULL;
652 size_t tmpbuflen = 512;
658 tmpbuf = alloca (tmpbuflen);
663 rc = gethostbyaddr_r (at2->addr,
664 ((at2->family == AF_INET6)
665 ? sizeof(struct in6_addr)
666 : sizeof(struct in_addr)),
667 at2->family, &th, tmpbuf, tmpbuflen,
671 while (rc == errno && herrno == NETDB_INTERNAL);
673 if (rc != 0 && herrno == NETDB_INTERNAL)
675 __set_h_errno (herrno);
680 c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
685 return GAIH_OKIFUNSPEC | -EAI_NONAME;
687 namelen = strlen (c) + 1;
692 #if __UCLIBC_HAS_IPV6__
693 if (at2->family == AF_INET6 || v4mapped)
696 socklen = sizeof (struct sockaddr_in6);
702 socklen = sizeof (struct sockaddr_in);
705 for (st2 = st; st2 != NULL; st2 = st2->next)
707 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
711 (*pai)->ai_flags = req->ai_flags;
712 (*pai)->ai_family = family;
713 (*pai)->ai_socktype = st2->socktype;
714 (*pai)->ai_protocol = st2->protocol;
715 (*pai)->ai_addrlen = socklen;
716 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
718 (*pai)->ai_addr->sa_len = socklen;
720 (*pai)->ai_addr->sa_family = family;
722 #if __UCLIBC_HAS_IPV6__
723 if (family == AF_INET6)
725 struct sockaddr_in6 *sin6p =
726 (struct sockaddr_in6 *) (*pai)->ai_addr;
728 sin6p->sin6_flowinfo = 0;
729 if (at2->family == AF_INET6)
731 memcpy (&sin6p->sin6_addr,
732 at2->addr, sizeof (struct in6_addr));
736 sin6p->sin6_addr.s6_addr32[0] = 0;
737 sin6p->sin6_addr.s6_addr32[1] = 0;
738 sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
739 memcpy(&sin6p->sin6_addr.s6_addr32[3],
740 at2->addr, sizeof (sin6p->sin6_addr.s6_addr32[3]));
742 sin6p->sin6_port = st2->port;
743 sin6p->sin6_scope_id = at2->scopeid;
748 struct sockaddr_in *sinp =
749 (struct sockaddr_in *) (*pai)->ai_addr;
751 memcpy (&sinp->sin_addr,
752 at2->addr, sizeof (struct in_addr));
753 sinp->sin_port = st2->port;
754 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
759 (*pai)->ai_canonname = ((void *) (*pai) +
760 sizeof (struct addrinfo) + socklen);
761 strcpy ((*pai)->ai_canonname, c);
764 (*pai)->ai_canonname = NULL;
766 (*pai)->ai_next = NULL;
767 pai = &((*pai)->ai_next);
776 static struct gaih gaih[] =
778 #if __UCLIBC_HAS_IPV6__
779 { PF_INET6, gaih_inet },
781 { PF_INET, gaih_inet },
783 { PF_LOCAL, gaih_local },
789 freeaddrinfo (struct addrinfo *ai)
800 libc_hidden_proto(freeaddrinfo)
801 libc_hidden_def(freeaddrinfo)
804 getaddrinfo (const char *name, const char *service,
805 const struct addrinfo *hints, struct addrinfo **pai)
807 int i = 0, j = 0, last_i = 0;
808 struct addrinfo *p = NULL, **end;
809 struct gaih *g = gaih, *pg = NULL;
810 struct gaih_service gaih_service, *pservice;
812 if (name != NULL && name[0] == '*' && name[1] == 0)
815 if (service != NULL && service[0] == '*' && service[1] == 0)
818 if (name == NULL && service == NULL)
822 hints = &default_hints;
824 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
825 AI_ADDRCONFIG|AI_V4MAPPED|AI_ALL))
828 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
831 if (service && service[0])
834 gaih_service.name = service;
835 gaih_service.num = strtoul (gaih_service.name, &c, 10);
837 gaih_service.num = -1;
840 * Can't specify a numerical socket unless a protocol
843 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
845 pservice = &gaih_service;
857 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
859 if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family))
862 if (pg == NULL || pg->gaih != g->gaih)
865 i = g->gaih (name, pservice, hints, end);
870 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
876 return -(i & GAIH_EAI);
879 while(*end) end = &((*end)->ai_next);
894 if (pai == NULL && last_i == 0)
900 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
902 libc_hidden_proto(getaddrinfo)
903 libc_hidden_def(getaddrinfo)