remove __xnet_getaddrinfo
[unleashed.git] / usr / src / lib / libc / port / inet / getaddrinfo.c
blob6b4e484facb8a197c23459be2d3d120c81eab164
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
29 #include <netdb.h>
30 #include <arpa/inet.h>
31 #include <nss_dbdefs.h>
32 #include <netinet/in.h>
33 #include <sys/socket.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <stdio.h>
37 #include <ctype.h>
38 #include <sys/types.h>
39 #include <stdlib.h>
40 #include <libintl.h>
41 #include <net/if.h>
43 #define ai2sin(x) ((struct sockaddr_in *)((x)->ai_addr))
44 #define ai2sin6(x) ((struct sockaddr_in6 *)((x)->ai_addr))
46 #define HOST_BROADCAST "255.255.255.255"
48 #pragma weak __xnet_getaddrinfo = getaddrinfo
51 * Storage allocation for global variables in6addr_any and
52 * in6addr_loopback. The extern declarations for these
53 * variables are defined in <netinet/in.h>. These two
54 * variables could have been defined in any of the "C" files
55 * in libc. They are defined here with other IPv6 related interfaces.
57 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
58 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
60 /* AI_MASK: all valid flags for addrinfo */
61 #define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST \
62 | AI_ADDRCONFIG | AI_NUMERICSERV | AI_V4MAPPED | AI_ALL)
63 #define ANY 0
66 * This is a private, undocumented, flag that getaddrinfo() uses for
67 * getipnodebyname(). In the case of AI_ADDRCONFIG && AI_V4MAPPED, if there are
68 * no IPv6 addresses, getaddrinfo() should return non-IPv4 mapped addresses. On
69 * the flip side, getipnodebyname() is defined by RFC 2553 to explicitly do so.
70 * Therefore this private flag indicates to getaddrinfo that we shouldn't do
71 * this.
73 #define AI_ADDRINFO 0x8000
75 /* function prototypes for used by getaddrinfo() routine */
76 static int get_addr(int family, const char *hostname, struct addrinfo *aip,
77 struct addrinfo *cur, ushort_t port);
78 static uint_t getscopeidfromzone(const struct sockaddr_in6 *sa,
79 const char *zone, uint32_t *sin6_scope_id);
80 static boolean_t str_isnumber(const char *p);
83 * getaddrinfo:
85 * Purpose:
86 * Routine for performing Address-to-nodename in a
87 * protocol-independent fashion.
88 * Description and history of the routine:
89 * Nodename-to-address translation is done in a protocol-
90 * independent fashion using the getaddrinfo() function
91 * that is taken from the IEEE POSIX 1003.1g.
93 * The official specification for this function will be the
94 * final POSIX standard, with the following additional
95 * requirements:
97 * - getaddrinfo() must be thread safe
98 * - The AI_NUMERICHOST is new.
99 * - All fields in socket address structures returned by
101 * getaddrinfo() that are not filled in through an explicit
102 * argument (e.g., sin6_flowinfo and sin_zero) must be set to 0.
103 * (This makes it easier to compare socket address structures).
105 * Input Parameters:
106 * nodename - pointer to null-terminated strings that represents
107 * a hostname or literal ip address (IPv4/IPv6) or this
108 * pointer can be NULL.
109 * servname - pointer to null-terminated strings that represents
110 * a servicename or literal port number or this
111 * pointer can be NULL.
112 * hints - optional argument that points to an addrinfo structure
113 * to provide hints on the type of socket that the caller
114 * supports.
115 * Possible setting of the ai_flags member of the hints structure:
116 * AI_PASSIVE - If set, the caller plans to use the returned socket
117 * address in a call to bind(). In this case, it the
118 * nodename argument is NULL, then the IP address portion
119 * of the socket address structure will be set to
120 * INADDR_ANY for IPv4 or IN6ADDR_ANY_INIT for IPv6.
121 * AI_PASSIVE - If not set, then the returned socket address will be
122 * ready for a call to connect() (for conn-oriented) or
123 * connect(), sendto(), or sendmsg() (for connectionless).
124 * In this case, if nodename is NULL, then the IP address
125 * portion of the socket address structure will be set to
126 * the loopback address.
127 * AI_CANONNAME - If set, then upon successful return the ai_canonname
128 * field of the first addrinfo structure in the linked
129 * list will point to a NULL-terminated string
130 * containing the canonical name of the specified nodename.
131 * AI_NUMERICHOST - If set, then a non-NULL nodename string must be a numeric
132 * host address string. Otherwise an error of EAI_NONAME
133 * is returned. This flag prevents any type of name
134 * resolution service from being called.
135 * AI_NUMERICSERV - If set, then a non-null servname string supplied shall
136 * be a numeric port string. Otherwise, an [EAI_NONAME]
137 * error shall be returned. This flag shall prevent any
138 * type of name resolution service from being invoked.
139 * AI_V4MAPPED - If set, along with an ai_family of AF_INET6, then
140 * getaddrinfo() shall return IPv4-mapped IPv6 addresses
141 * on finding no matching IPv6 addresses ( ai_addrlen shall
142 * be 16). The AI_V4MAPPED flag shall be ignored unless
143 * ai_family equals AF_INET6.
144 * AI_ALL - If the AI_ALL flag is used with the AI_V4MAPPED flag,
145 * then getaddrinfo() shall return all matching IPv6 and
146 * IPv4 addresses. The AI_ALL flag without the AI_V4MAPPED
147 * flag is ignored.
148 * Output Parameters:
149 * res - upon successful return a pointer to a linked list of one
150 * or more addrinfo structures is returned through this
151 * argument. The caller can process each addrinfo structures
152 * in this list by following the ai_next pointer, until a
153 * NULL pointer is encountered. In each returned addrinfo
154 * structure the three members ai_family, ai_socktype, and
155 * ai_protocol are corresponding arguments for a call to the
156 * socket() function. In each addrinfo structure the ai_addr
157 * field points to filled-in socket address structure whose
158 * length is specified by the ai_addrlen member.
160 * Return Value:
161 * This function returns 0 upon success or a nonzero error code. The
162 * following names are nonzero error codes from getaddrinfo(), and are
163 * defined in <netdb.h>.
164 * EAI_ADDRFAMILY - address family not supported
165 * EAI_AGAIN - DNS temporary failure
166 * EAI_BADFLAGS - invalid ai_flags
167 * EAI_FAIL - DNS non-recoverable failure
168 * EAI_FAMILY - ai_family not supported
169 * EAI_MEMORY - memory allocation failure
170 * EAI_NODATA - no address associated with nodename
171 * EAI_NONAME - host/servname not known
172 * EAI_SERVICE - servname not supported for ai_socktype
173 * EAI_SOCKTYPE - ai_socktype not supported
174 * EAI_SYSTEM - system error in errno
176 * Memory Allocation:
177 * All of the information returned by getaddrinfo() is dynamically
178 * allocated: the addrinfo structures, and the socket address
179 * structures and canonical node name strings pointed to by the
180 * addrinfo structures.
184 static int
185 _getaddrinfo(const char *hostname, const char *servname,
186 const struct addrinfo *hints, struct addrinfo **res)
188 struct addrinfo *cur;
189 struct addrinfo *aip;
190 struct addrinfo ai;
191 int error;
192 ushort_t port;
194 cur = &ai;
195 aip = &ai;
197 aip->ai_flags = 0;
198 aip->ai_family = PF_UNSPEC;
199 aip->ai_socktype = 0;
200 aip->ai_protocol = 0;
201 aip->ai_addrlen = 0;
202 aip->ai_canonname = NULL;
203 aip->ai_addr = NULL;
204 aip->ai_next = NULL;
205 port = 0;
207 /* if nodename nor servname provided */
208 if (hostname == NULL && servname == NULL) {
209 *res = NULL;
210 return (EAI_NONAME);
212 if (hints != NULL) {
213 /* check for bad flags in hints */
214 if ((hints->ai_flags != 0) && (hints->ai_flags & ~AI_MASK)) {
215 *res = NULL;
216 return (EAI_BADFLAGS);
218 if ((hostname == NULL || *hostname == '\0') &&
219 (hints->ai_flags & AI_CANONNAME)) {
220 *res = NULL;
221 return (EAI_BADFLAGS);
223 if (hints->ai_family != PF_UNSPEC &&
224 hints->ai_family != PF_INET &&
225 hints->ai_family != PF_INET6) {
226 *res = NULL;
227 return (EAI_FAMILY);
230 (void) memcpy(aip, hints, sizeof (*aip));
231 switch (aip->ai_socktype) {
232 case ANY:
233 switch (aip->ai_protocol) {
234 case ANY:
235 break;
236 case IPPROTO_UDP:
237 aip->ai_socktype = SOCK_DGRAM;
238 break;
239 case IPPROTO_TCP:
240 case IPPROTO_SCTP:
241 aip->ai_socktype = SOCK_STREAM;
242 break;
243 default:
244 aip->ai_socktype = SOCK_RAW;
245 break;
247 break;
248 case SOCK_RAW:
249 break;
250 case SOCK_SEQPACKET:
252 * If the hint does not have a preference on the
253 * protocol, use SCTP as the default for
254 * SOCK_SEQPACKET.
256 if (aip->ai_protocol == ANY)
257 aip->ai_protocol = IPPROTO_SCTP;
258 break;
259 case SOCK_DGRAM:
260 aip->ai_protocol = IPPROTO_UDP;
261 break;
262 case SOCK_STREAM:
264 * If the hint does not have a preference on the
265 * protocol, use TCP as the default for SOCK_STREAM.
267 if (aip->ai_protocol == ANY)
268 aip->ai_protocol = IPPROTO_TCP;
269 break;
270 default:
271 *res = NULL;
272 return (EAI_SOCKTYPE);
277 * Get the service.
280 if (servname != NULL) {
281 struct servent result;
282 int bufsize = 128;
283 char *buf = NULL;
284 struct servent *sp;
285 char *proto = NULL;
287 switch (aip->ai_socktype) {
288 case ANY:
289 proto = NULL;
290 break;
291 case SOCK_DGRAM:
292 proto = "udp";
293 break;
294 case SOCK_STREAM:
296 * If there is no hint given, use TCP as the default
297 * protocol.
299 switch (aip->ai_protocol) {
300 case ANY:
301 case IPPROTO_TCP:
302 default:
303 proto = "tcp";
304 break;
305 case IPPROTO_SCTP:
306 proto = "sctp";
307 break;
309 break;
310 case SOCK_SEQPACKET:
311 /* Default to SCTP if no hint given. */
312 switch (aip->ai_protocol) {
313 case ANY:
314 default:
315 proto = "sctp";
316 break;
318 break;
321 * Servname string can be a decimal port number.
322 * If we already know the socket type there is no need
323 * to call getservbyport.
325 if (aip->ai_flags & AI_NUMERICSERV) {
326 if (!str_isnumber(servname)) {
327 return (EAI_NONAME);
329 port = htons(atoi(servname));
330 } else if (str_isnumber(servname)) {
331 port = htons(atoi(servname));
332 if (aip->ai_socktype == ANY) {
333 do {
334 free(buf);
335 bufsize *= 2;
336 buf = malloc(bufsize);
337 if (buf == NULL) {
338 *res = NULL;
339 return (EAI_MEMORY);
342 sp = getservbyport_r(port, proto,
343 &result, buf, bufsize);
344 if (sp == NULL && errno != ERANGE) {
345 free(buf);
346 *res = NULL;
347 return (EAI_SERVICE);
350 * errno == ERANGE so our scratch buffer space
351 * wasn't big enough. Double it and try
352 * again.
354 } while (sp == NULL);
356 } else {
357 do {
358 free(buf);
359 bufsize *= 2;
360 buf = malloc(bufsize);
361 if (buf == NULL) {
362 *res = NULL;
363 return (EAI_MEMORY);
366 sp = getservbyname_r(servname, proto, &result,
367 buf, bufsize);
368 if (sp == NULL && errno != ERANGE) {
369 free(buf);
370 *res = NULL;
371 return (EAI_SERVICE);
374 * errno == ERANGE so our scratch buffer space wasn't
375 * big enough. Double it and try again.
377 } while (sp == NULL);
379 port = sp->s_port;
381 if (aip->ai_socktype == ANY) {
382 if (aip->ai_flags & AI_NUMERICSERV) {
384 * RFC 2553bis doesn't allow us to use the
385 * any resolver to find out if there is a
386 * match. We could walk the service file
387 * with *servent(). Given the commonality of
388 * calling getaddrinfo() with a number and
389 * ANY protocol we won't add that at this time.
391 return (EAI_NONAME);
394 if (strcmp(sp->s_proto, "udp") == 0) {
395 aip->ai_socktype = SOCK_DGRAM;
396 aip->ai_protocol = IPPROTO_UDP;
397 } else if (strcmp(sp->s_proto, "tcp") == 0) {
398 aip->ai_socktype = SOCK_STREAM;
399 aip->ai_protocol = IPPROTO_TCP;
400 } else if (strcmp(sp->s_proto, "sctp") == 0) {
401 aip->ai_socktype = SOCK_STREAM;
402 aip->ai_protocol = IPPROTO_SCTP;
403 } else {
404 free(buf);
406 *res = NULL;
407 errno = EPROTONOSUPPORT;
408 return (EAI_SYSTEM);
412 free(buf);
416 * hostname is NULL
417 * case 1: AI_PASSIVE bit set : anyaddr 0.0.0.0 or ::
418 * case 2: AI_PASSIVE bit not set : localhost 127.0.0.1 or ::1
421 if (hostname == NULL) {
422 struct addrinfo *nai;
423 socklen_t addrlen;
424 char *canonname;
426 if (aip->ai_family == PF_INET)
427 goto v4only;
428 /* create IPv6 addrinfo */
429 nai = malloc(sizeof (struct addrinfo));
430 if (nai == NULL)
431 goto nomem;
432 *nai = *aip;
433 addrlen = sizeof (struct sockaddr_in6);
434 nai->ai_addr = malloc(addrlen);
435 if (nai->ai_addr == NULL) {
436 freeaddrinfo(nai);
437 goto nomem;
439 bzero(nai->ai_addr, addrlen);
440 nai->ai_addrlen = addrlen;
441 nai->ai_family = PF_INET6;
442 nai->ai_canonname = NULL;
443 if (nai->ai_flags & AI_PASSIVE) {
444 ai2sin6(nai)->sin6_addr = in6addr_any;
445 } else {
446 ai2sin6(nai)->sin6_addr = in6addr_loopback;
447 if (nai->ai_flags & AI_CANONNAME) {
448 canonname = strdup("loopback");
449 if (canonname == NULL) {
450 freeaddrinfo(nai);
451 goto nomem;
453 nai->ai_canonname = canonname;
456 ai2sin6(nai)->sin6_family = PF_INET6;
457 ai2sin6(nai)->sin6_port = port;
458 cur->ai_next = nai;
459 cur = nai;
460 if (aip->ai_family == PF_INET6) {
461 cur->ai_next = NULL;
462 goto success;
464 /* If address family is PF_UNSPEC or PF_INET */
465 v4only:
466 /* create IPv4 addrinfo */
467 nai = malloc(sizeof (struct addrinfo));
468 if (nai == NULL)
469 goto nomem;
470 *nai = *aip;
471 addrlen = sizeof (struct sockaddr_in);
472 nai->ai_addr = malloc(addrlen);
473 if (nai->ai_addr == NULL) {
474 freeaddrinfo(nai);
475 goto nomem;
477 bzero(nai->ai_addr, addrlen);
478 nai->ai_addrlen = addrlen;
479 nai->ai_family = PF_INET;
480 nai->ai_canonname = NULL;
481 if (nai->ai_flags & AI_PASSIVE) {
482 ai2sin(nai)->sin_addr.s_addr = INADDR_ANY;
483 } else {
484 ai2sin(nai)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
485 if (nai->ai_flags & AI_CANONNAME &&
486 nai->ai_family != PF_UNSPEC) {
487 canonname = strdup("loopback");
488 if (canonname == NULL) {
489 freeaddrinfo(nai);
490 goto nomem;
492 nai->ai_canonname = canonname;
495 ai2sin(nai)->sin_family = PF_INET;
496 ai2sin(nai)->sin_port = port;
497 cur->ai_next = nai;
498 cur = nai;
499 cur->ai_next = NULL;
500 goto success;
503 /* hostname string is a literal address or an alphabetical name */
504 error = get_addr(aip->ai_family, hostname, aip, cur, port);
505 if (error) {
506 *res = NULL;
507 return (error);
510 success:
511 *res = aip->ai_next;
512 return (0);
514 nomem:
515 return (EAI_MEMORY);
519 getaddrinfo(const char *hostname, const char *servname,
520 const struct addrinfo *hints, struct addrinfo **res)
522 return _getaddrinfo(hostname, servname, hints, res);
525 static int
526 get_addr(int family, const char *hostname, struct addrinfo *aip, struct
527 addrinfo *cur, ushort_t port)
529 struct hostent *hp;
530 char _hostname[MAXHOSTNAMELEN];
531 int i, errnum;
532 struct addrinfo *nai;
533 int addrlen;
534 char *canonname;
535 boolean_t firsttime = B_TRUE;
536 boolean_t create_v6_addrinfo;
537 struct in_addr v4addr;
538 struct in6_addr v6addr;
539 struct in6_addr *v6addrp;
540 char *zonestr = NULL;
543 * Check for existence of address-zoneid delimiter '%'
544 * If the delimiter exists, parse the zoneid portion of
545 * <addr>%<zone_id>
547 if ((zonestr = strchr(hostname, '%')) != NULL) {
548 /* make sure we have room for <addr> portion of hostname */
549 if (((zonestr - hostname) + 1) > sizeof (_hostname)) {
550 return (EAI_MEMORY);
553 /* chop off and save <zone_id> portion */
554 (void) strlcpy(_hostname, hostname, (zonestr - hostname) + 1);
555 ++zonestr; /* make zonestr point at start of <zone-id> */
556 /* ensure zone is valid */
557 if ((*zonestr == '\0') || (strlen(zonestr) > LIFNAMSIZ)) {
558 return (EAI_NONAME);
560 } else {
561 size_t hlen = sizeof (_hostname);
563 if (strlcpy(_hostname, hostname, hlen) >= hlen) {
564 return (EAI_MEMORY);
568 /* Check to see if AI_NUMERICHOST bit is set */
569 if (aip->ai_flags & AI_NUMERICHOST) {
570 /* check to see if _hostname points to a literal IP address */
571 if (!((inet_addr(_hostname) != ((in_addr_t)-1)) ||
572 (strcmp(_hostname, HOST_BROADCAST) == 0) ||
573 (inet_pton(AF_INET6, _hostname, &v6addr) > 0))) {
574 return (EAI_NONAME);
578 /* if hostname argument is literal, name service doesn't get called */
579 if (family == PF_UNSPEC) {
580 hp = getipnodebyname(_hostname, AF_INET6, AI_ALL |
581 aip->ai_flags | AI_V4MAPPED | AI_ADDRINFO, &errnum);
582 } else {
583 hp = getipnodebyname(_hostname, family, aip->ai_flags, &errnum);
586 if (hp == NULL) {
587 switch (errnum) {
588 case HOST_NOT_FOUND:
589 return (EAI_NONAME);
590 case TRY_AGAIN:
591 return (EAI_AGAIN);
592 case NO_RECOVERY:
593 return (EAI_FAIL);
594 case NO_ADDRESS:
595 return (EAI_NONAME);
596 default:
597 return (EAI_SYSTEM);
601 for (i = 0; hp->h_addr_list[i]; i++) {
602 /* Determine if an IPv6 addrinfo structure should be created */
603 create_v6_addrinfo = B_TRUE;
604 if (hp->h_addrtype == AF_INET6) {
605 v6addrp = (struct in6_addr *)hp->h_addr_list[i];
606 if (!(aip->ai_flags & AI_V4MAPPED) &&
607 IN6_IS_ADDR_V4MAPPED(v6addrp)) {
608 create_v6_addrinfo = B_FALSE;
609 IN6_V4MAPPED_TO_INADDR(v6addrp, &v4addr);
611 } else if (hp->h_addrtype == AF_INET) {
612 create_v6_addrinfo = B_FALSE;
613 (void) memcpy(&v4addr, hp->h_addr_list[i],
614 sizeof (struct in_addr));
615 } else {
616 return (EAI_SYSTEM);
619 if (create_v6_addrinfo) {
620 /* create IPv6 addrinfo */
621 nai = malloc(sizeof (struct addrinfo));
622 if (nai == NULL)
623 goto nomem;
624 *nai = *aip;
625 addrlen = sizeof (struct sockaddr_in6);
626 nai->ai_addr = malloc(addrlen);
627 if (nai->ai_addr == NULL) {
628 freeaddrinfo(nai);
629 goto nomem;
631 bzero(nai->ai_addr, addrlen);
632 nai->ai_addrlen = addrlen;
633 nai->ai_family = PF_INET6;
635 (void) memcpy(ai2sin6(nai)->sin6_addr.s6_addr,
636 hp->h_addr_list[i], sizeof (struct in6_addr));
637 nai->ai_canonname = NULL;
638 if ((nai->ai_flags & AI_CANONNAME) && firsttime) {
639 canonname = strdup(hp->h_name);
640 if (canonname == NULL) {
641 freeaddrinfo(nai);
642 goto nomem;
644 nai->ai_canonname = canonname;
645 firsttime = B_FALSE;
647 ai2sin6(nai)->sin6_family = PF_INET6;
648 ai2sin6(nai)->sin6_port = port;
649 /* set sin6_scope_id */
650 if (zonestr != NULL) {
652 * Translate 'zonestr' into a valid
653 * sin6_scope_id.
655 if ((errnum =
656 getscopeidfromzone(ai2sin6(nai), zonestr,
657 &ai2sin6(nai)->sin6_scope_id)) != 0) {
658 return (errnum);
660 } else {
661 ai2sin6(nai)->sin6_scope_id = 0;
663 } else {
664 /* create IPv4 addrinfo */
665 nai = malloc(sizeof (struct addrinfo));
666 if (nai == NULL)
667 goto nomem;
668 *nai = *aip;
669 addrlen = sizeof (struct sockaddr_in);
670 nai->ai_addr = malloc(addrlen);
671 if (nai->ai_addr == NULL) {
672 freeaddrinfo(nai);
673 goto nomem;
675 bzero(nai->ai_addr, addrlen);
676 nai->ai_addrlen = addrlen;
677 nai->ai_family = PF_INET;
678 (void) memcpy(&(ai2sin(nai)->sin_addr.s_addr),
679 &v4addr, sizeof (struct in_addr));
680 nai->ai_canonname = NULL;
681 if (nai->ai_flags & AI_CANONNAME && firsttime) {
682 canonname = strdup(hp->h_name);
683 if (canonname == NULL) {
684 freeaddrinfo(nai);
685 goto nomem;
687 nai->ai_canonname = canonname;
688 firsttime = B_FALSE;
690 ai2sin(nai)->sin_family = PF_INET;
691 ai2sin(nai)->sin_port = port;
694 cur->ai_next = nai;
695 cur = nai;
697 cur->ai_next = NULL;
698 freehostent(hp);
699 return (0);
701 nomem:
702 freehostent(hp);
703 return (EAI_MEMORY);
708 * getscopeidfromzone(sa, zone, sin6_scope_id)
710 * Converts the string pointed to by 'zone' into a sin6_scope_id.
711 * 'zone' will either be a pointer to an interface name or will
712 * be a literal sin6_scope_id.
714 * 0 is returned on success and the output parameter 'sin6_scope_id' will
715 * be set to a valid sin6_scope_id.
716 * EAI_NONAME is returned for either of two reasons:
717 * 1. The IPv6 address pointed to by sa->sin6_addr is not
718 * part of the 'link scope' (ie link local, nodelocal multicast or
719 * linklocal multicast address)
720 * 2. The string pointed to by 'zone' can not be translate to a valid
721 * sin6_scope_id.
723 static uint_t
724 getscopeidfromzone(const struct sockaddr_in6 *sa, const char *zone,
725 uint32_t *sin6_scope_id) {
726 const in6_addr_t *addr = &sa->sin6_addr;
727 ulong_t ul_scope_id;
728 char *endp;
730 if (IN6_IS_ADDR_LINKSCOPE(addr)) {
732 * Look up interface index associated with interface name
733 * pointed to by 'zone'. Since the address is part of the link
734 * scope, there is a one-to-one relationship between interface
735 * index and sin6_scope_id.
736 * If an interface index can not be found for 'zone', then
737 * treat 'zone' as a literal sin6_scope_id value.
739 if ((*sin6_scope_id = if_nametoindex(zone)) != 0) {
740 return (0);
741 } else {
742 if ((ul_scope_id = strtoul(zone, &endp, 10)) != 0) {
743 /* check that entire string was read */
744 if (*endp != '\0') {
745 return (EAI_NONAME);
747 *sin6_scope_id =
748 (uint32_t)(ul_scope_id & 0xffffffffUL);
749 } else {
750 return (EAI_NONAME);
753 } else {
754 return (EAI_NONAME);
756 return (0);
760 void
761 freeaddrinfo(struct addrinfo *ai)
763 struct addrinfo *next;
765 do {
766 next = ai->ai_next;
767 free(ai->ai_canonname);
768 free(ai->ai_addr);
769 free(ai);
770 ai = next;
771 } while (ai != NULL);
774 static boolean_t
775 str_isnumber(const char *p)
777 char *q = (char *)p;
778 while (*q) {
779 if (!isdigit(*q))
780 return (B_FALSE);
781 q++;
783 return (B_TRUE);
785 static const char *gai_errlist[] = {
786 "name translation error 0 (no error)", /* 0 */
787 "specified address family not supported", /* 1 EAI_ADDRFAMILY */
788 "temporary name resolution failure", /* 2 EAI_AGAIN */
789 "invalid flags", /* 3 EAI_BADFLAGS */
790 "non-recoverable name resolution failure", /* 4 EAI_FAIL */
791 "specified address family not supported", /* 5 EAI_FAMILY */
792 "memory allocation failure", /* 6 EAI_MEMORY */
793 "no address for the specified node name", /* 7 EAI_NODATA */
794 "node name or service name not known", /* 8 EAI_NONAME */
795 "service name not available for the specified socket type",
796 /* 9 EAI_SERVICE */
797 "specified socket type not supported", /* 10 EAI_SOCKTYPE */
798 "system error", /* 11 EAI_SYSTEM */
800 static int gai_nerr = { sizeof (gai_errlist)/sizeof (gai_errlist[0]) };
802 const char *
803 gai_strerror(int ecode)
805 if (ecode < 0)
806 return (dgettext(TEXT_DOMAIN,
807 "name translation internal error"));
808 else if (ecode < gai_nerr)
809 return (dgettext(TEXT_DOMAIN, gai_errlist[ecode]));
810 return (dgettext(TEXT_DOMAIN, "unknown name translation error"));