1 /* The Inner Net License, Version 2.00
3 The author(s) grant permission for redistribution and use in source and
4 binary forms, with or without modification, of the software and documentation
5 provided that the following conditions are met:
7 0. If you receive a version of the software that is specifically labelled
8 as not being for redistribution (check the version message and/or README),
9 you are not permitted to redistribute that version of the software in any
11 1. All terms of the all other applicable copyrights and licenses must be
13 2. Redistributions of source code must retain the authors' copyright
14 notice(s), this list of conditions, and the following disclaimer.
15 3. Redistributions in binary form must reproduce the authors' copyright
16 notice(s), this list of conditions, and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18 4. All advertising materials mentioning features or use of this software
19 must display the following acknowledgement with the name(s) of the
20 authors as specified in the copyright notice(s) substituted where
23 This product includes software developed by <name(s)>, The Inner
24 Net, and other contributors.
26 5. Neither the name(s) of the author(s) nor the names of its contributors
27 may be used to endorse or promote products derived from this software
28 without specific prior written permission.
30 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
31 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
37 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 If these license terms cause you a real problem, contact the author. */
43 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
53 #include <arpa/inet.h>
54 #include <sys/socket.h>
55 #include <netinet/in.h>
56 #include <sys/types.h>
58 #include <sys/utsname.h>
61 #define GAIH_OKIFUNSPEC 0x0100
62 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
65 #define UNIX_PATH_MAX 108
76 struct gaih_servtuple *next;
82 static struct gaih_servtuple nullserv = { NULL, 0, 0, 0 };
86 struct gaih_addrtuple *next;
100 /* Values for `protoflag'. */
101 #define GAI_PROTO_NOSERVICE 1
103 static struct gaih_typeproto gaih_inet_typeproto[] =
106 { SOCK_STREAM, IPPROTO_TCP, (char *) "tcp", 0 },
107 { SOCK_DGRAM, IPPROTO_UDP, (char *) "udp", 0 },
108 { SOCK_RAW, IPPROTO_RAW, (char *) "raw", GAI_PROTO_NOSERVICE },
115 int (*gaih)(const char *name, const struct gaih_service *service,
116 const struct addrinfo *req, struct addrinfo **pai);
119 static struct addrinfo default_hints =
120 { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
124 gaih_local (const char *name, const struct gaih_service *service,
125 const struct addrinfo *req, struct addrinfo **pai)
127 struct utsname utsname;
129 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
130 return GAIH_OKIFUNSPEC | -EAI_NONAME;
132 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
133 if (uname (&utsname) < 0)
138 if (strcmp(name, "localhost") &&
139 strcmp(name, "local") &&
140 strcmp(name, "unix") &&
141 strcmp(name, utsname.nodename))
142 return GAIH_OKIFUNSPEC | -EAI_NONAME;
145 if (req->ai_protocol || req->ai_socktype)
147 struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
149 while (tp->name != NULL
150 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
151 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
152 || (req->ai_protocol != 0
153 && req->ai_protocol != tp->protocol)))
156 if (tp->name == NULL)
158 if (req->ai_socktype)
159 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
161 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
165 *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
166 + ((req->ai_flags & AI_CANONNAME)
167 ? (strlen(utsname.nodename) + 1): 0));
171 (*pai)->ai_next = NULL;
172 (*pai)->ai_flags = req->ai_flags;
173 (*pai)->ai_family = AF_LOCAL;
174 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
175 (*pai)->ai_protocol = req->ai_protocol;
176 (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
177 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
180 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
181 sizeof (struct sockaddr_un);
184 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
185 memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
189 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
191 if (strchr (service->name, '/') != NULL)
193 if (strlen (service->name) >= sizeof (sunp->sun_path))
194 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
196 strcpy (sunp->sun_path, service->name);
200 if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
201 sizeof (sunp->sun_path))
202 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
204 __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
209 /* This is a dangerous use of the interface since there is a time
210 window between the test for the file and the actual creation
211 (done by the caller) in which a file with the same name could
213 char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
215 if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
217 || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
221 if (req->ai_flags & AI_CANONNAME)
222 (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
223 + sizeof (struct sockaddr_un),
226 (*pai)->ai_canonname = NULL;
231 gaih_inet_serv (const char *servicename, struct gaih_typeproto *tp,
232 struct gaih_servtuple *st)
235 size_t tmpbuflen = 1024;
242 tmpbuf = __alloca (tmpbuflen);
244 r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
246 if (r != 0 || s == NULL)
251 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
257 st->socktype = tp->socktype;
258 st->protocol = tp->protocol;
259 st->port = s->s_port;
264 #define gethosts(_family, _type) \
273 tmpbuf = __alloca (tmpbuflen); \
274 rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \
275 tmpbuflen, &h, &herrno); \
276 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
279 if (herrno == NETDB_INTERNAL) \
281 __set_h_errno (herrno); \
282 return -EAI_SYSTEM; \
284 if (herrno == TRY_AGAIN) \
286 __set_h_errno (herrno); \
292 for (i = 0; h->h_addr_list[i]; i++) \
295 *pat = __alloca (sizeof(struct gaih_addrtuple)); \
296 (*pat)->next = NULL; \
297 (*pat)->family = _family; \
298 memcpy ((*pat)->addr, h->h_addr_list[i], \
300 pat = &((*pat)->next); \
303 no_data = rc != 0 && herrno == NO_DATA; \
307 gaih_inet (const char *name, const struct gaih_service *service,
308 const struct addrinfo *req, struct addrinfo **pai)
310 struct gaih_typeproto *tp = gaih_inet_typeproto;
311 struct gaih_servtuple *st = &nullserv;
312 struct gaih_addrtuple *at = NULL;
315 if (req->ai_protocol || req->ai_socktype)
319 while (tp->name != NULL
320 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
321 || (req->ai_protocol != 0
322 && req->ai_protocol != tp->protocol)))
325 if (tp->name == NULL)
327 if (req->ai_socktype)
328 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
330 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
336 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
337 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
339 if (service->num < 0)
341 if (tp->name != NULL)
343 st = (struct gaih_servtuple *)
344 __alloca (sizeof (struct gaih_servtuple));
346 if ((rc = gaih_inet_serv (service->name, tp, st)))
351 struct gaih_servtuple **pst = &st;
352 for (tp++; tp->name; tp++)
354 struct gaih_servtuple *newp;
356 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
359 if (req->ai_socktype != 0
360 && req->ai_socktype != tp->socktype)
363 newp = (struct gaih_servtuple *)
364 __alloca (sizeof (struct gaih_servtuple));
366 if ((rc = gaih_inet_serv (service->name, tp, newp)))
368 if (rc & GAIH_OKIFUNSPEC)
377 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
382 st = __alloca (sizeof (struct gaih_servtuple));
384 st->socktype = tp->socktype;
385 st->protocol = tp->protocol;
386 st->port = htons (service->num);
389 else if (req->ai_socktype || req->ai_protocol)
391 st = __alloca (sizeof (struct gaih_servtuple));
393 st->socktype = req->ai_socktype;
394 st->protocol = req->ai_protocol;
399 /* Neither socket type nor protocol is set. Return all socket types
401 struct gaih_servtuple **lastp = &st;
402 for (++tp; tp->name != NULL; ++tp)
404 struct gaih_servtuple *newp;
406 newp = __alloca (sizeof (struct gaih_servtuple));
408 newp->socktype = tp->socktype;
409 newp->protocol = tp->protocol;
419 at = __alloca (sizeof (struct gaih_addrtuple));
421 at->family = AF_UNSPEC;
425 if (inet_pton (AF_INET, name, at->addr) > 0)
427 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
428 at->family = AF_INET;
430 return -EAI_ADDRFAMILY;
433 if (at->family == AF_UNSPEC)
435 char *namebuf = strdupa (name);
438 scope_delim = strchr (namebuf, SCOPE_DELIMITER);
439 if (scope_delim != NULL)
442 if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
444 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
445 at->family = AF_INET6;
447 return -EAI_ADDRFAMILY;
449 if (scope_delim != NULL)
451 int try_numericscope = 0;
452 if (IN6_IS_ADDR_LINKLOCAL (at->addr)
453 || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
455 at->scopeid = if_nametoindex (scope_delim + 1);
456 if (at->scopeid == 0)
457 try_numericscope = 1;
460 try_numericscope = 1;
462 if (try_numericscope != 0)
465 assert (sizeof (uint32_t) <= sizeof (unsigned long));
466 at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
469 return GAIH_OKIFUNSPEC | -EAI_NONAME;
475 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
478 struct gaih_addrtuple **pat = &at;
481 int old_res_options = _res.options;
483 /* If we are looking for both IPv4 and IPv6 address we don't
484 want the lookup functions to automatically promote IPv4
485 addresses to IPv6 addresses. Currently this is decided
486 by setting the RES_USE_INET6 bit in _res.options. */
487 if (req->ai_family == AF_UNSPEC)
488 _res.options &= ~RES_USE_INET6;
490 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
491 gethosts (AF_INET6, struct in6_addr);
492 no_inet6_data = no_data;
494 if (req->ai_family == AF_UNSPEC)
495 _res.options = old_res_options;
497 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
498 gethosts (AF_INET, struct in_addr);
500 if (no_data != 0 && no_inet6_data != 0)
501 /* We made requests but they turned out no data. The name
503 return (GAIH_OKIFUNSPEC | -EAI_NODATA);
506 if (at->family == AF_UNSPEC)
507 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
511 struct gaih_addrtuple *atr;
512 atr = at = __alloca (sizeof (struct gaih_addrtuple));
513 memset (at, '\0', sizeof (struct gaih_addrtuple));
515 if (req->ai_family == 0)
517 at->next = __alloca (sizeof (struct gaih_addrtuple));
518 memset (at->next, '\0', sizeof (struct gaih_addrtuple));
521 if (req->ai_family == 0 || req->ai_family == AF_INET6)
523 at->family = AF_INET6;
524 if ((req->ai_flags & AI_PASSIVE) == 0)
525 memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
529 if (req->ai_family == 0 || req->ai_family == AF_INET)
531 atr->family = AF_INET;
532 if ((req->ai_flags & AI_PASSIVE) == 0)
533 *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
541 const char *c = NULL;
542 struct gaih_servtuple *st2;
543 struct gaih_addrtuple *at2 = at;
544 size_t socklen, namelen;
547 buffer is the size of an unformatted IPv6 address in printable format.
549 char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
553 if (req->ai_flags & AI_CANONNAME)
555 struct hostent *h = NULL;
559 size_t tmpbuflen = 512;
565 tmpbuf = __alloca (tmpbuflen);
570 rc = __gethostbyaddr_r (at2->addr,
571 ((at2->family == AF_INET6)
572 ? sizeof(struct in6_addr)
573 : sizeof(struct in_addr)),
574 at2->family, &th, tmpbuf, tmpbuflen,
578 while (rc == errno && herrno == NETDB_INTERNAL);
580 if (rc != 0 && herrno == NETDB_INTERNAL)
582 __set_h_errno (herrno);
587 c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
592 return GAIH_OKIFUNSPEC | -EAI_NONAME;
594 namelen = strlen (c) + 1;
599 if (at2->family == AF_INET6)
600 socklen = sizeof (struct sockaddr_in6);
602 socklen = sizeof (struct sockaddr_in);
604 for (st2 = st; st2 != NULL; st2 = st2->next)
606 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
610 (*pai)->ai_flags = req->ai_flags;
611 (*pai)->ai_family = at2->family;
612 (*pai)->ai_socktype = st2->socktype;
613 (*pai)->ai_protocol = st2->protocol;
614 (*pai)->ai_addrlen = socklen;
615 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
617 (*pai)->ai_addr->sa_len = socklen;
619 (*pai)->ai_addr->sa_family = at2->family;
621 if (at2->family == AF_INET6)
623 struct sockaddr_in6 *sin6p =
624 (struct sockaddr_in6 *) (*pai)->ai_addr;
626 sin6p->sin6_flowinfo = 0;
627 memcpy (&sin6p->sin6_addr,
628 at2->addr, sizeof (struct in6_addr));
629 sin6p->sin6_port = st2->port;
630 sin6p->sin6_scope_id = at2->scopeid;
634 struct sockaddr_in *sinp =
635 (struct sockaddr_in *) (*pai)->ai_addr;
636 memcpy (&sinp->sin_addr,
637 at2->addr, sizeof (struct in_addr));
638 sinp->sin_port = st2->port;
639 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
644 (*pai)->ai_canonname = ((void *) (*pai) +
645 sizeof (struct addrinfo) + socklen);
646 strcpy ((*pai)->ai_canonname, c);
649 (*pai)->ai_canonname = NULL;
651 (*pai)->ai_next = NULL;
652 pai = &((*pai)->ai_next);
661 static struct gaih gaih[] =
663 { PF_INET6, gaih_inet },
664 { PF_INET, gaih_inet },
665 { PF_LOCAL, gaih_local },
670 getaddrinfo (const char *name, const char *service,
671 const struct addrinfo *hints, struct addrinfo **pai)
673 int i = 0, j = 0, last_i = 0;
674 struct addrinfo *p = NULL, **end;
675 struct gaih *g = gaih, *pg = NULL;
676 struct gaih_service gaih_service, *pservice;
678 if (name != NULL && name[0] == '*' && name[1] == 0)
681 if (service != NULL && service[0] == '*' && service[1] == 0)
684 if (name == NULL && service == NULL)
688 hints = &default_hints;
690 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST))
693 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
696 if (service && service[0])
699 gaih_service.name = service;
700 gaih_service.num = strtoul (gaih_service.name, &c, 10);
702 gaih_service.num = -1;
704 /* Can't specify a numerical socket unless a protocol family was
706 if (hints->ai_socktype == 0)
708 pservice = &gaih_service;
720 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
723 if (pg == NULL || pg->gaih != g->gaih)
726 i = g->gaih (name, pservice, hints, end);
729 /* EAI_NODATA is a more specific result as it says that
730 we found a result but it is not usable. */
731 if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA))
734 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
740 return -(i & GAIH_EAI);
743 while(*end) end = &((*end)->ai_next);
758 if (pai == NULL && last_i == 0)
764 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
768 freeaddrinfo (struct addrinfo *ai)