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 libc_hidden_proto(memcpy)
71 libc_hidden_proto(memset)
72 /* libc_hidden_proto(strcmp) */
73 /* libc_hidden_proto(stpcpy) */
74 libc_hidden_proto(strchr)
75 libc_hidden_proto(strcpy)
76 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 __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 __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 __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 __UCLIBC_HAS_IPV6__
684 if (at2->family == AF_INET6 || v4mapped)
687 socklen = sizeof (struct sockaddr_in6);
693 socklen = sizeof (struct sockaddr_in);
696 for (st2 = st; st2 != NULL; st2 = st2->next)
698 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
702 (*pai)->ai_flags = req->ai_flags;
703 (*pai)->ai_family = family;
704 (*pai)->ai_socktype = st2->socktype;
705 (*pai)->ai_protocol = st2->protocol;
706 (*pai)->ai_addrlen = socklen;
707 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
709 (*pai)->ai_addr->sa_len = socklen;
711 (*pai)->ai_addr->sa_family = family;
713 #if __UCLIBC_HAS_IPV6__
714 if (family == AF_INET6)
716 struct sockaddr_in6 *sin6p =
717 (struct sockaddr_in6 *) (*pai)->ai_addr;
719 sin6p->sin6_flowinfo = 0;
720 if (at2->family == AF_INET6)
722 memcpy (&sin6p->sin6_addr,
723 at2->addr, sizeof (struct in6_addr));
727 sin6p->sin6_addr.s6_addr32[0] = 0;
728 sin6p->sin6_addr.s6_addr32[1] = 0;
729 sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
730 memcpy(&sin6p->sin6_addr.s6_addr32[3],
731 at2->addr, sizeof (sin6p->sin6_addr.s6_addr32[3]));
733 sin6p->sin6_port = st2->port;
734 sin6p->sin6_scope_id = at2->scopeid;
739 struct sockaddr_in *sinp =
740 (struct sockaddr_in *) (*pai)->ai_addr;
742 memcpy (&sinp->sin_addr,
743 at2->addr, sizeof (struct in_addr));
744 sinp->sin_port = st2->port;
745 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
750 (*pai)->ai_canonname = ((void *) (*pai) +
751 sizeof (struct addrinfo) + socklen);
752 strcpy ((*pai)->ai_canonname, c);
755 (*pai)->ai_canonname = NULL;
757 (*pai)->ai_next = NULL;
758 pai = &((*pai)->ai_next);
767 static struct gaih gaih[] =
769 #if __UCLIBC_HAS_IPV6__
770 { PF_INET6, gaih_inet },
772 { PF_INET, gaih_inet },
774 { PF_LOCAL, gaih_local },
779 libc_hidden_proto(freeaddrinfo)
781 freeaddrinfo (struct addrinfo *ai)
792 libc_hidden_def(freeaddrinfo)
794 libc_hidden_proto(getaddrinfo)
796 getaddrinfo (const char *name, const char *service,
797 const struct addrinfo *hints, struct addrinfo **pai)
799 int i = 0, j = 0, last_i = 0;
800 struct addrinfo *p = NULL, **end;
801 struct gaih *g = gaih, *pg = NULL;
802 struct gaih_service gaih_service, *pservice;
804 if (name != NULL && name[0] == '*' && name[1] == 0)
807 if (service != NULL && service[0] == '*' && service[1] == 0)
810 if (name == NULL && service == NULL)
814 hints = &default_hints;
816 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
817 AI_ADDRCONFIG|AI_V4MAPPED|AI_NUMERICSERV|AI_ALL))
820 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
823 if (service && service[0])
826 gaih_service.name = service;
827 gaih_service.num = strtoul (gaih_service.name, &c, 10);
829 if (hints->ai_flags & AI_NUMERICSERV)
832 gaih_service.num = -1;
836 * Can't specify a numerical socket unless a protocol
839 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
841 pservice = &gaih_service;
853 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
855 if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family))
858 if (pg == NULL || pg->gaih != g->gaih)
861 i = g->gaih (name, pservice, hints, end);
866 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
872 return -(i & GAIH_EAI);
875 while(*end) end = &((*end)->ai_next);
890 if (pai == NULL && last_i == 0)
896 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
898 libc_hidden_def(getaddrinfo)