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. */
58 #include <arpa/inet.h>
59 #include <sys/socket.h>
60 #include <netinet/in.h>
61 #include <sys/types.h>
63 #include <sys/utsname.h>
66 /* The following declarations and definitions have been removed from
67 * the public header since we don't want people to use them. */
68 #define AI_V4MAPPED 0x0008 /* IPv4-mapped addresses are acceptable. */
69 #define AI_ALL 0x0010 /* Return both IPv4 and IPv6 addresses. */
70 #define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose
71 returned address type. */
72 #define AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG)
75 #define GAIH_OKIFUNSPEC 0x0100
76 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
79 #define UNIX_PATH_MAX 108
90 struct gaih_servtuple *next;
96 static const struct gaih_servtuple nullserv;
100 struct gaih_addrtuple *next;
106 struct gaih_typeproto
114 /* Values for `protoflag'. */
115 #define GAI_PROTO_NOSERVICE 1
116 #define GAI_PROTO_PROTOANY 2
118 static const struct gaih_typeproto gaih_inet_typeproto[] =
121 { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
122 { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
123 { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
130 int (*gaih)(const char *name, const struct gaih_service *service,
131 const struct addrinfo *req, struct addrinfo **pai);
135 static const struct addrinfo default_hints;
137 static const struct addrinfo default_hints =
138 { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
142 static int addrconfig (sa_family_t af)
146 int saved_errno = errno;
147 s = socket(af, SOCK_DGRAM, 0);
149 ret = (errno == EMFILE) ? 1 : 0;
155 __set_errno (saved_errno);
160 /* Using Unix sockets this way is a security risk. */
162 gaih_local (const char *name, const struct gaih_service *service,
163 const struct addrinfo *req, struct addrinfo **pai)
165 struct utsname utsname;
167 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
168 return GAIH_OKIFUNSPEC | -EAI_NONAME;
170 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
171 if (uname (&utsname) < 0)
176 if (strcmp(name, "localhost") &&
177 strcmp(name, "local") &&
178 strcmp(name, "unix") &&
179 strcmp(name, utsname.nodename))
180 return GAIH_OKIFUNSPEC | -EAI_NONAME;
183 if (req->ai_protocol || req->ai_socktype)
185 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
188 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
189 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
190 || (req->ai_protocol != 0
191 && !(tp->protoflag & GAI_PROTO_PROTOANY)
192 && req->ai_protocol != tp->protocol)))
197 if (req->ai_socktype)
198 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
200 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
204 *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
205 + ((req->ai_flags & AI_CANONNAME)
206 ? (strlen(utsname.nodename) + 1): 0));
210 (*pai)->ai_next = NULL;
211 (*pai)->ai_flags = req->ai_flags;
212 (*pai)->ai_family = AF_LOCAL;
213 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
214 (*pai)->ai_protocol = req->ai_protocol;
215 (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
216 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
219 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
220 sizeof (struct sockaddr_un);
223 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
224 memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
228 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
230 if (strchr (service->name, '/') != NULL)
232 if (strlen (service->name) >= sizeof (sunp->sun_path))
233 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
235 strcpy (sunp->sun_path, service->name);
239 if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
240 sizeof (sunp->sun_path))
241 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
243 __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
248 /* This is a dangerous use of the interface since there is a time
249 window between the test for the file and the actual creation
250 (done by the caller) in which a file with the same name could
252 char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
254 if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
256 || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
260 if (req->ai_flags & AI_CANONNAME)
261 (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
262 + sizeof (struct sockaddr_un),
265 (*pai)->ai_canonname = NULL;
271 gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
272 const struct addrinfo *req, struct gaih_servtuple *st)
275 size_t tmpbuflen = 1024;
282 tmpbuf = alloca (tmpbuflen);
284 r = getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
286 if (r != 0 || s == NULL)
291 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
297 st->socktype = tp->socktype;
298 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
299 ? req->ai_protocol : tp->protocol);
300 st->port = s->s_port;
305 #define gethosts(_family, _type) \
315 tmpbuf = alloca (tmpbuflen); \
316 rc = gethostbyname2_r (name, _family, &th, tmpbuf, \
317 tmpbuflen, &h, &herrno); \
318 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
321 if (herrno == NETDB_INTERNAL) \
323 __set_h_errno (herrno); \
324 return -EAI_SYSTEM; \
326 if (herrno == TRY_AGAIN) \
327 no_data = EAI_AGAIN; \
329 no_data = herrno == NO_DATA; \
331 else if (h != NULL) \
333 for (i = 0; h->h_addr_list[i]; i++) \
335 if (*pat == NULL) { \
336 *pat = alloca (sizeof(struct gaih_addrtuple)); \
337 (*pat)->scopeid = 0; \
339 (*pat)->next = NULL; \
340 (*pat)->family = _family; \
341 memcpy ((*pat)->addr, h->h_addr_list[i], \
343 pat = &((*pat)->next); \
349 gaih_inet (const char *name, const struct gaih_service *service,
350 const struct addrinfo *req, struct addrinfo **pai)
352 const struct gaih_typeproto *tp = gaih_inet_typeproto;
353 struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
354 struct gaih_addrtuple *at = NULL;
356 int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6) &&
357 (req->ai_flags & AI_V4MAPPED);
359 if (req->ai_protocol || req->ai_socktype)
364 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
365 || (req->ai_protocol != 0
366 && !(tp->protoflag & GAI_PROTO_PROTOANY)
367 && req->ai_protocol != tp->protocol)))
372 if (req->ai_socktype)
373 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
375 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
381 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
382 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
384 if (service->num < 0)
388 st = (struct gaih_servtuple *)
389 alloca (sizeof (struct gaih_servtuple));
391 if ((rc = gaih_inet_serv (service->name, tp, req, st)))
396 struct gaih_servtuple **pst = &st;
397 for (tp++; tp->name[0]; tp++)
399 struct gaih_servtuple *newp;
401 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
404 if (req->ai_socktype != 0
405 && req->ai_socktype != tp->socktype)
407 if (req->ai_protocol != 0
408 && !(tp->protoflag & GAI_PROTO_PROTOANY)
409 && req->ai_protocol != tp->protocol)
412 newp = (struct gaih_servtuple *)
413 alloca (sizeof (struct gaih_servtuple));
415 if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
417 if (rc & GAIH_OKIFUNSPEC)
425 if (st == (struct gaih_servtuple *) &nullserv)
426 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
431 st = alloca (sizeof (struct gaih_servtuple));
433 st->socktype = tp->socktype;
434 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
435 ? req->ai_protocol : tp->protocol);
436 st->port = htons (service->num);
439 else if (req->ai_socktype || req->ai_protocol)
441 st = alloca (sizeof (struct gaih_servtuple));
443 st->socktype = tp->socktype;
444 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
445 ? req->ai_protocol : tp->protocol);
451 * Neither socket type nor protocol is set. Return all socket types
454 struct gaih_servtuple **lastp = &st;
455 for (++tp; tp->name[0]; ++tp)
457 struct gaih_servtuple *newp;
459 newp = alloca (sizeof (struct gaih_servtuple));
461 newp->socktype = tp->socktype;
462 newp->protocol = tp->protocol;
472 at = alloca (sizeof (struct gaih_addrtuple));
474 at->family = AF_UNSPEC;
478 if (inet_pton (AF_INET, name, at->addr) > 0)
480 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
481 at->family = AF_INET;
486 #if __UCLIBC_HAS_IPV6__
487 if (at->family == AF_UNSPEC)
489 char *namebuf = strdupa (name);
492 scope_delim = strchr (namebuf, SCOPE_DELIMITER);
493 if (scope_delim != NULL)
496 if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
498 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
499 at->family = AF_INET6;
503 if (scope_delim != NULL)
505 int try_numericscope = 0;
506 if (IN6_IS_ADDR_LINKLOCAL (at->addr)
507 || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
509 at->scopeid = if_nametoindex (scope_delim + 1);
510 if (at->scopeid == 0)
511 try_numericscope = 1;
514 try_numericscope = 1;
516 if (try_numericscope != 0)
519 assert (sizeof (uint32_t) <= sizeof (unsigned long));
520 at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
523 return GAIH_OKIFUNSPEC | -EAI_NONAME;
530 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
533 struct gaih_addrtuple **pat = &at;
538 * If we are looking for both IPv4 and IPv6 address we don't want
539 * the lookup functions to automatically promote IPv4 addresses to
543 #if __UCLIBC_HAS_IPV6__
544 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
545 gethosts (AF_INET6, struct in6_addr);
547 no_inet6_data = no_data;
549 if (req->ai_family == AF_INET ||
550 (!v4mapped && req->ai_family == AF_UNSPEC) ||
551 (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL))))
552 gethosts (AF_INET, struct in_addr);
554 if (no_data != 0 && no_inet6_data != 0)
556 /* If both requests timed out report this. */
557 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
561 * We made requests but they turned out no data.
562 * The name is known, though.
564 return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
568 if (at->family == AF_UNSPEC)
569 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
573 struct gaih_addrtuple *atr;
574 atr = at = alloca (sizeof (struct gaih_addrtuple));
575 memset (at, '\0', sizeof (struct gaih_addrtuple));
577 if (req->ai_family == 0)
579 at->next = alloca (sizeof (struct gaih_addrtuple));
580 memset (at->next, '\0', sizeof (struct gaih_addrtuple));
583 #if __UCLIBC_HAS_IPV6__
584 if (req->ai_family == 0 || req->ai_family == AF_INET6)
586 at->family = AF_INET6;
587 if ((req->ai_flags & AI_PASSIVE) == 0)
588 memcpy (at->addr, &__in6addr_loopback, sizeof (struct in6_addr));
593 if (req->ai_family == 0 || req->ai_family == AF_INET)
595 atr->family = AF_INET;
596 if ((req->ai_flags & AI_PASSIVE) == 0)
597 *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
605 const char *c = NULL;
606 struct gaih_servtuple *st2;
607 struct gaih_addrtuple *at2 = at;
608 size_t socklen, namelen;
612 * buffer is the size of an unformatted IPv6 address in
615 char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
619 if (req->ai_flags & AI_CANONNAME)
621 struct hostent *h = NULL;
625 size_t tmpbuflen = 512;
631 tmpbuf = alloca (tmpbuflen);
636 rc = gethostbyaddr_r (at2->addr,
637 ((at2->family == AF_INET6)
638 ? sizeof(struct in6_addr)
639 : sizeof(struct in_addr)),
640 at2->family, &th, tmpbuf, tmpbuflen,
644 while (rc == errno && herrno == NETDB_INTERNAL);
646 if (rc != 0 && herrno == NETDB_INTERNAL)
648 __set_h_errno (herrno);
653 c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
658 return GAIH_OKIFUNSPEC | -EAI_NONAME;
660 namelen = strlen (c) + 1;
665 #if __UCLIBC_HAS_IPV6__
666 if (at2->family == AF_INET6 || v4mapped)
669 socklen = sizeof (struct sockaddr_in6);
675 socklen = sizeof (struct sockaddr_in);
678 for (st2 = st; st2 != NULL; st2 = st2->next)
680 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
684 (*pai)->ai_flags = req->ai_flags;
685 (*pai)->ai_family = family;
686 (*pai)->ai_socktype = st2->socktype;
687 (*pai)->ai_protocol = st2->protocol;
688 (*pai)->ai_addrlen = socklen;
689 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
691 (*pai)->ai_addr->sa_len = socklen;
693 (*pai)->ai_addr->sa_family = family;
695 #if __UCLIBC_HAS_IPV6__
696 if (family == AF_INET6)
698 struct sockaddr_in6 *sin6p =
699 (struct sockaddr_in6 *) (*pai)->ai_addr;
701 sin6p->sin6_flowinfo = 0;
702 if (at2->family == AF_INET6)
704 memcpy (&sin6p->sin6_addr,
705 at2->addr, sizeof (struct in6_addr));
709 sin6p->sin6_addr.s6_addr32[0] = 0;
710 sin6p->sin6_addr.s6_addr32[1] = 0;
711 sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
712 memcpy(&sin6p->sin6_addr.s6_addr32[3],
713 at2->addr, sizeof (sin6p->sin6_addr.s6_addr32[3]));
715 sin6p->sin6_port = st2->port;
716 sin6p->sin6_scope_id = at2->scopeid;
721 struct sockaddr_in *sinp =
722 (struct sockaddr_in *) (*pai)->ai_addr;
724 memcpy (&sinp->sin_addr,
725 at2->addr, sizeof (struct in_addr));
726 sinp->sin_port = st2->port;
727 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
732 (*pai)->ai_canonname = ((void *) (*pai) +
733 sizeof (struct addrinfo) + socklen);
734 strcpy ((*pai)->ai_canonname, c);
737 (*pai)->ai_canonname = NULL;
739 (*pai)->ai_next = NULL;
740 pai = &((*pai)->ai_next);
749 static struct gaih gaih[] =
751 #if __UCLIBC_HAS_IPV6__
752 { PF_INET6, gaih_inet },
754 { PF_INET, gaih_inet },
756 { PF_LOCAL, gaih_local },
762 getaddrinfo (const char *name, const char *service,
763 const struct addrinfo *hints, struct addrinfo **pai)
765 int i = 0, j = 0, last_i = 0;
766 struct addrinfo *p = NULL, **end;
767 struct gaih *g = gaih, *pg = NULL;
768 struct gaih_service gaih_service, *pservice;
770 if (name != NULL && name[0] == '*' && name[1] == 0)
773 if (service != NULL && service[0] == '*' && service[1] == 0)
776 if (name == NULL && service == NULL)
780 hints = &default_hints;
782 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
783 AI_ADDRCONFIG|AI_V4MAPPED|AI_ALL))
786 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
789 if (service && service[0])
792 gaih_service.name = service;
793 gaih_service.num = strtoul (gaih_service.name, &c, 10);
795 gaih_service.num = -1;
798 * Can't specify a numerical socket unless a protocol
801 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
803 pservice = &gaih_service;
815 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
817 if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family))
820 if (pg == NULL || pg->gaih != g->gaih)
823 i = g->gaih (name, pservice, hints, end);
828 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
834 return -(i & GAIH_EAI);
837 while(*end) end = &((*end)->ai_next);
852 if (pai == NULL && last_i == 0)
858 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
862 freeaddrinfo (struct addrinfo *ai)