1 /* $USAGI: getaddrinfo.c,v 1.16 2001/10/04 09:52:03 sekiya Exp $ */
3 /* The Inner Net License, Version 2.00
5 The author(s) grant permission for redistribution and use in source and
6 binary forms, with or without modification, of the software and documentation
7 provided that the following conditions are met:
9 0. If you receive a version of the software that is specifically labelled
10 as not being for redistribution (check the version message and/or README),
11 you are not permitted to redistribute that version of the software in any
13 1. All terms of the all other applicable copyrights and licenses must be
15 2. Redistributions of source code must retain the authors' copyright
16 notice(s), this list of conditions, and the following disclaimer.
17 3. Redistributions in binary form must reproduce the authors' copyright
18 notice(s), this list of conditions, and the following disclaimer in the
19 documentation and/or other materials provided with the distribution.
20 4. All advertising materials mentioning features or use of this software
21 must display the following acknowledgement with the name(s) of the
22 authors as specified in the copyright notice(s) substituted where
25 This product includes software developed by <name(s)>, The Inner
26 Net, and other contributors.
28 5. Neither the name(s) of the author(s) nor the names of its contributors
29 may be used to endorse or promote products derived from this software
30 without specific prior written permission.
32 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
33 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
39 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 If these license terms cause you a real problem, contact the author. */
45 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
47 #define getservbyname_r __getservbyname_r
48 #define gethostbyname_r __gethostbyname_r
49 #define gethostbyname2_r __gethostbyname2_r
50 #define gethostbyaddr_r __gethostbyaddr_r
51 #define inet_pton __inet_pton
52 #define inet_ntop __inet_ntop
53 #define strtoul __strtoul
56 #define stpcpy __stpcpy
57 /* strdupa is using these */
58 #define memcpy __memcpy
59 #define strlen __strlen
73 #include <arpa/inet.h>
74 #include <sys/socket.h>
75 #include <netinet/in.h>
76 #include <sys/types.h>
78 #include <sys/utsname.h>
81 /* The following declarations and definitions have been removed from
82 * the public header since we don't want people to use them. */
83 #define AI_V4MAPPED 0x0008 /* IPv4-mapped addresses are acceptable. */
84 #define AI_ALL 0x0010 /* Return both IPv4 and IPv6 addresses. */
85 #define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose
86 returned address type. */
87 #define AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG)
90 #define GAIH_OKIFUNSPEC 0x0100
91 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
94 #define UNIX_PATH_MAX 108
103 struct gaih_servtuple
105 struct gaih_servtuple *next;
111 static const struct gaih_servtuple nullserv;
113 struct gaih_addrtuple
115 struct gaih_addrtuple *next;
121 struct gaih_typeproto
129 /* Values for `protoflag'. */
130 #define GAI_PROTO_NOSERVICE 1
131 #define GAI_PROTO_PROTOANY 2
133 static const struct gaih_typeproto gaih_inet_typeproto[] =
136 { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
137 { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
138 { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
145 int (*gaih)(const char *name, const struct gaih_service *service,
146 const struct addrinfo *req, struct addrinfo **pai);
150 static const struct addrinfo default_hints;
152 static const struct addrinfo default_hints =
153 { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
157 static int addrconfig (sa_family_t af)
161 int saved_errno = errno;
162 s = socket(af, SOCK_DGRAM, 0);
164 ret = (errno == EMFILE) ? 1 : 0;
170 __set_errno (saved_errno);
175 /* Using Unix sockets this way is a security risk. */
177 gaih_local (const char *name, const struct gaih_service *service,
178 const struct addrinfo *req, struct addrinfo **pai)
180 struct utsname utsname;
182 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
183 return GAIH_OKIFUNSPEC | -EAI_NONAME;
185 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
186 if (uname (&utsname) < 0)
191 if (__strcmp(name, "localhost") &&
192 __strcmp(name, "local") &&
193 __strcmp(name, "unix") &&
194 __strcmp(name, utsname.nodename))
195 return GAIH_OKIFUNSPEC | -EAI_NONAME;
198 if (req->ai_protocol || req->ai_socktype)
200 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
203 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
204 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
205 || (req->ai_protocol != 0
206 && !(tp->protoflag & GAI_PROTO_PROTOANY)
207 && req->ai_protocol != tp->protocol)))
212 if (req->ai_socktype)
213 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
215 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
219 *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
220 + ((req->ai_flags & AI_CANONNAME)
221 ? (__strlen(utsname.nodename) + 1): 0));
225 (*pai)->ai_next = NULL;
226 (*pai)->ai_flags = req->ai_flags;
227 (*pai)->ai_family = AF_LOCAL;
228 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
229 (*pai)->ai_protocol = req->ai_protocol;
230 (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
231 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
234 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
235 sizeof (struct sockaddr_un);
238 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
239 __memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
243 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
245 if (__strchr (service->name, '/') != NULL)
247 if (__strlen (service->name) >= sizeof (sunp->sun_path))
248 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
250 __strcpy (sunp->sun_path, service->name);
254 if (__strlen (P_tmpdir "/") + 1 + __strlen (service->name) >=
255 sizeof (sunp->sun_path))
256 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
258 stpcpy (stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
263 /* This is a dangerous use of the interface since there is a time
264 window between the test for the file and the actual creation
265 (done by the caller) in which a file with the same name could
267 char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
269 if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
271 || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
275 if (req->ai_flags & AI_CANONNAME)
276 (*pai)->ai_canonname = __strcpy ((char *) *pai + sizeof (struct addrinfo)
277 + sizeof (struct sockaddr_un),
280 (*pai)->ai_canonname = NULL;
286 gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
287 const struct addrinfo *req, struct gaih_servtuple *st)
290 size_t tmpbuflen = 1024;
297 tmpbuf = alloca (tmpbuflen);
299 r = getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
301 if (r != 0 || s == NULL)
306 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
312 st->socktype = tp->socktype;
313 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
314 ? req->ai_protocol : tp->protocol);
315 st->port = s->s_port;
320 #define gethosts(_family, _type) \
330 tmpbuf = alloca (tmpbuflen); \
331 rc = gethostbyname2_r (name, _family, &th, tmpbuf, \
332 tmpbuflen, &h, &herrno); \
333 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
336 if (herrno == NETDB_INTERNAL) \
338 __set_h_errno (herrno); \
339 return -EAI_SYSTEM; \
341 if (herrno == TRY_AGAIN) \
342 no_data = EAI_AGAIN; \
344 no_data = herrno == NO_DATA; \
346 else if (h != NULL) \
348 for (i = 0; h->h_addr_list[i]; i++) \
350 if (*pat == NULL) { \
351 *pat = alloca (sizeof(struct gaih_addrtuple)); \
352 (*pat)->scopeid = 0; \
354 (*pat)->next = NULL; \
355 (*pat)->family = _family; \
356 __memcpy ((*pat)->addr, h->h_addr_list[i], \
358 pat = &((*pat)->next); \
364 gaih_inet (const char *name, const struct gaih_service *service,
365 const struct addrinfo *req, struct addrinfo **pai)
367 const struct gaih_typeproto *tp = gaih_inet_typeproto;
368 struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
369 struct gaih_addrtuple *at = NULL;
371 int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6) &&
372 (req->ai_flags & AI_V4MAPPED);
374 if (req->ai_protocol || req->ai_socktype)
379 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
380 || (req->ai_protocol != 0
381 && !(tp->protoflag & GAI_PROTO_PROTOANY)
382 && req->ai_protocol != tp->protocol)))
387 if (req->ai_socktype)
388 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
390 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
396 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
397 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
399 if (service->num < 0)
403 st = (struct gaih_servtuple *)
404 alloca (sizeof (struct gaih_servtuple));
406 if ((rc = gaih_inet_serv (service->name, tp, req, st)))
411 struct gaih_servtuple **pst = &st;
412 for (tp++; tp->name[0]; tp++)
414 struct gaih_servtuple *newp;
416 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
419 if (req->ai_socktype != 0
420 && req->ai_socktype != tp->socktype)
422 if (req->ai_protocol != 0
423 && !(tp->protoflag & GAI_PROTO_PROTOANY)
424 && req->ai_protocol != tp->protocol)
427 newp = (struct gaih_servtuple *)
428 alloca (sizeof (struct gaih_servtuple));
430 if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
432 if (rc & GAIH_OKIFUNSPEC)
440 if (st == (struct gaih_servtuple *) &nullserv)
441 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
446 st = alloca (sizeof (struct gaih_servtuple));
448 st->socktype = tp->socktype;
449 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
450 ? req->ai_protocol : tp->protocol);
451 st->port = htons (service->num);
454 else if (req->ai_socktype || req->ai_protocol)
456 st = alloca (sizeof (struct gaih_servtuple));
458 st->socktype = tp->socktype;
459 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
460 ? req->ai_protocol : tp->protocol);
466 * Neither socket type nor protocol is set. Return all socket types
469 struct gaih_servtuple **lastp = &st;
470 for (++tp; tp->name[0]; ++tp)
472 struct gaih_servtuple *newp;
474 newp = alloca (sizeof (struct gaih_servtuple));
476 newp->socktype = tp->socktype;
477 newp->protocol = tp->protocol;
487 at = alloca (sizeof (struct gaih_addrtuple));
489 at->family = AF_UNSPEC;
493 if (inet_pton (AF_INET, name, at->addr) > 0)
495 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
496 at->family = AF_INET;
501 #if __UCLIBC_HAS_IPV6__
502 if (at->family == AF_UNSPEC)
504 char *namebuf = strdupa (name);
507 scope_delim = __strchr (namebuf, SCOPE_DELIMITER);
508 if (scope_delim != NULL)
511 if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
513 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
514 at->family = AF_INET6;
518 if (scope_delim != NULL)
520 int try_numericscope = 0;
521 if (IN6_IS_ADDR_LINKLOCAL (at->addr)
522 || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
524 at->scopeid = if_nametoindex (scope_delim + 1);
525 if (at->scopeid == 0)
526 try_numericscope = 1;
529 try_numericscope = 1;
531 if (try_numericscope != 0)
534 assert (sizeof (uint32_t) <= sizeof (unsigned long));
535 at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
538 return GAIH_OKIFUNSPEC | -EAI_NONAME;
545 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
548 struct gaih_addrtuple **pat = &at;
553 * If we are looking for both IPv4 and IPv6 address we don't want
554 * the lookup functions to automatically promote IPv4 addresses to
558 #if __UCLIBC_HAS_IPV6__
559 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
560 gethosts (AF_INET6, struct in6_addr);
562 no_inet6_data = no_data;
564 if (req->ai_family == AF_INET ||
565 (!v4mapped && req->ai_family == AF_UNSPEC) ||
566 (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL))))
567 gethosts (AF_INET, struct in_addr);
569 if (no_data != 0 && no_inet6_data != 0)
571 /* If both requests timed out report this. */
572 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
576 * We made requests but they turned out no data.
577 * The name is known, though.
579 return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
583 if (at->family == AF_UNSPEC)
584 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
588 struct gaih_addrtuple *atr;
589 atr = at = alloca (sizeof (struct gaih_addrtuple));
590 __memset (at, '\0', sizeof (struct gaih_addrtuple));
592 if (req->ai_family == 0)
594 at->next = alloca (sizeof (struct gaih_addrtuple));
595 __memset (at->next, '\0', sizeof (struct gaih_addrtuple));
598 #if __UCLIBC_HAS_IPV6__
599 if (req->ai_family == 0 || req->ai_family == AF_INET6)
601 extern const struct in6_addr __in6addr_loopback;
602 at->family = AF_INET6;
603 if ((req->ai_flags & AI_PASSIVE) == 0)
604 __memcpy (at->addr, &__in6addr_loopback, sizeof (struct in6_addr));
609 if (req->ai_family == 0 || req->ai_family == AF_INET)
611 atr->family = AF_INET;
612 if ((req->ai_flags & AI_PASSIVE) == 0)
613 *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
621 const char *c = NULL;
622 struct gaih_servtuple *st2;
623 struct gaih_addrtuple *at2 = at;
624 size_t socklen, namelen;
628 * buffer is the size of an unformatted IPv6 address in
631 char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
635 if (req->ai_flags & AI_CANONNAME)
637 struct hostent *h = NULL;
641 size_t tmpbuflen = 512;
647 tmpbuf = alloca (tmpbuflen);
652 rc = gethostbyaddr_r (at2->addr,
653 ((at2->family == AF_INET6)
654 ? sizeof(struct in6_addr)
655 : sizeof(struct in_addr)),
656 at2->family, &th, tmpbuf, tmpbuflen,
660 while (rc == errno && herrno == NETDB_INTERNAL);
662 if (rc != 0 && herrno == NETDB_INTERNAL)
664 __set_h_errno (herrno);
669 c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
674 return GAIH_OKIFUNSPEC | -EAI_NONAME;
676 namelen = __strlen (c) + 1;
681 #if __UCLIBC_HAS_IPV6__
682 if (at2->family == AF_INET6 || v4mapped)
685 socklen = sizeof (struct sockaddr_in6);
691 socklen = sizeof (struct sockaddr_in);
694 for (st2 = st; st2 != NULL; st2 = st2->next)
696 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
700 (*pai)->ai_flags = req->ai_flags;
701 (*pai)->ai_family = family;
702 (*pai)->ai_socktype = st2->socktype;
703 (*pai)->ai_protocol = st2->protocol;
704 (*pai)->ai_addrlen = socklen;
705 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
707 (*pai)->ai_addr->sa_len = socklen;
709 (*pai)->ai_addr->sa_family = family;
711 #if __UCLIBC_HAS_IPV6__
712 if (family == AF_INET6)
714 struct sockaddr_in6 *sin6p =
715 (struct sockaddr_in6 *) (*pai)->ai_addr;
717 sin6p->sin6_flowinfo = 0;
718 if (at2->family == AF_INET6)
720 __memcpy (&sin6p->sin6_addr,
721 at2->addr, sizeof (struct in6_addr));
725 sin6p->sin6_addr.s6_addr32[0] = 0;
726 sin6p->sin6_addr.s6_addr32[1] = 0;
727 sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
728 __memcpy(&sin6p->sin6_addr.s6_addr32[3],
729 at2->addr, sizeof (sin6p->sin6_addr.s6_addr32[3]));
731 sin6p->sin6_port = st2->port;
732 sin6p->sin6_scope_id = at2->scopeid;
737 struct sockaddr_in *sinp =
738 (struct sockaddr_in *) (*pai)->ai_addr;
740 __memcpy (&sinp->sin_addr,
741 at2->addr, sizeof (struct in_addr));
742 sinp->sin_port = st2->port;
743 __memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
748 (*pai)->ai_canonname = ((void *) (*pai) +
749 sizeof (struct addrinfo) + socklen);
750 __strcpy ((*pai)->ai_canonname, c);
753 (*pai)->ai_canonname = NULL;
755 (*pai)->ai_next = NULL;
756 pai = &((*pai)->ai_next);
765 static struct gaih gaih[] =
767 #if __UCLIBC_HAS_IPV6__
768 { PF_INET6, gaih_inet },
770 { PF_INET, gaih_inet },
772 { PF_LOCAL, gaih_local },
777 void attribute_hidden
778 __freeaddrinfo (struct addrinfo *ai)
789 strong_alias(__freeaddrinfo,freeaddrinfo)
792 __getaddrinfo (const char *name, const char *service,
793 const struct addrinfo *hints, struct addrinfo **pai)
795 int i = 0, j = 0, last_i = 0;
796 struct addrinfo *p = NULL, **end;
797 struct gaih *g = gaih, *pg = NULL;
798 struct gaih_service gaih_service, *pservice;
800 if (name != NULL && name[0] == '*' && name[1] == 0)
803 if (service != NULL && service[0] == '*' && service[1] == 0)
806 if (name == NULL && service == NULL)
810 hints = &default_hints;
812 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
813 AI_ADDRCONFIG|AI_V4MAPPED|AI_ALL))
816 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
819 if (service && service[0])
822 gaih_service.name = service;
823 gaih_service.num = strtoul (gaih_service.name, &c, 10);
825 gaih_service.num = -1;
828 * Can't specify a numerical socket unless a protocol
831 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
833 pservice = &gaih_service;
845 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
847 if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family))
850 if (pg == NULL || pg->gaih != g->gaih)
853 i = g->gaih (name, pservice, hints, end);
858 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
864 return -(i & GAIH_EAI);
867 while(*end) end = &((*end)->ai_next);
882 if (pai == NULL && last_i == 0)
888 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
890 strong_alias(__getaddrinfo,getaddrinfo)