8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libsocket / inet / getaddrinfo.c
blob99b769e41e684a502ab94ea5bbfa3dca5d873d29
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"
49 * getaddrinfo() returns EAI_NONAME in some cases, however
50 * since EAI_NONAME is not part of SUSv3 it needed to be
51 * masked in the standards compliant environment.
52 * GAIV_DEFAULT and GAIV_XPG6 accomplish this.
54 #define GAIV_DEFAULT 0
55 #define GAIV_XPG6 1
58 * Storage allocation for global variables in6addr_any and
59 * in6addr_loopback. The extern declarations for these
60 * variables are defined in <netinet/in.h>. These two
61 * variables could have been defined in any of the "C" files
62 * in libsocket. They are defined here with other IPv6
63 * related interfaces.
65 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
66 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
68 /* AI_MASK: all valid flags for addrinfo */
69 #define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST \
70 | AI_ADDRCONFIG | AI_NUMERICSERV | AI_V4MAPPED | AI_ALL)
71 #define ANY 0
74 * This is a private, undocumented, flag that getaddrinfo() uses for
75 * getipnodebyname(). In the case of AI_ADDRCONFIG && AI_V4MAPPED, if there are
76 * no IPv6 addresses, getaddrinfo() should return non-IPv4 mapped addresses. On
77 * the flip side, getipnodebyname() is defined by RFC 2553 to explicitly do so.
78 * Therefore this private flag indicates to getaddrinfo that we shouldn't do
79 * this.
81 #define AI_ADDRINFO 0x8000
83 /* function prototypes for used by getaddrinfo() routine */
84 static int get_addr(int family, const char *hostname, struct addrinfo *aip,
85 struct addrinfo *cur, ushort_t port, int version);
86 static uint_t getscopeidfromzone(const struct sockaddr_in6 *sa,
87 const char *zone, uint32_t *sin6_scope_id);
88 static boolean_t str_isnumber(const char *p);
91 * getaddrinfo:
93 * Purpose:
94 * Routine for performing Address-to-nodename in a
95 * protocol-independent fashion.
96 * Description and history of the routine:
97 * Nodename-to-address translation is done in a protocol-
98 * independent fashion using the getaddrinfo() function
99 * that is taken from the IEEE POSIX 1003.1g.
101 * The official specification for this function will be the
102 * final POSIX standard, with the following additional
103 * requirements:
105 * - getaddrinfo() must be thread safe
106 * - The AI_NUMERICHOST is new.
107 * - All fields in socket address structures returned by
109 * getaddrinfo() that are not filled in through an explicit
110 * argument (e.g., sin6_flowinfo and sin_zero) must be set to 0.
111 * (This makes it easier to compare socket address structures).
113 * Input Parameters:
114 * nodename - pointer to null-terminated strings that represents
115 * a hostname or literal ip address (IPv4/IPv6) or this
116 * pointer can be NULL.
117 * servname - pointer to null-terminated strings that represents
118 * a servicename or literal port number or this
119 * pointer can be NULL.
120 * hints - optional argument that points to an addrinfo structure
121 * to provide hints on the type of socket that the caller
122 * supports.
123 * Possible setting of the ai_flags member of the hints structure:
124 * AI_PASSIVE - If set, the caller plans to use the returned socket
125 * address in a call to bind(). In this case, it the
126 * nodename argument is NULL, then the IP address portion
127 * of the socket address structure will be set to
128 * INADDR_ANY for IPv4 or IN6ADDR_ANY_INIT for IPv6.
129 * AI_PASSIVE - If not set, then the returned socket address will be
130 * ready for a call to connect() (for conn-oriented) or
131 * connect(), sendto(), or sendmsg() (for connectionless).
132 * In this case, if nodename is NULL, then the IP address
133 * portion of the socket address structure will be set to
134 * the loopback address.
135 * AI_CANONNAME - If set, then upon successful return the ai_canonname
136 * field of the first addrinfo structure in the linked
137 * list will point to a NULL-terminated string
138 * containing the canonical name of the specified nodename.
139 * AI_NUMERICHOST - If set, then a non-NULL nodename string must be a numeric
140 * host address string. Otherwise an error of EAI_NONAME
141 * is returned. This flag prevents any type of name
142 * resolution service from being called.
143 * AI_NUMERICSERV - If set, then a non-null servname string supplied shall
144 * be a numeric port string. Otherwise, an [EAI_NONAME]
145 * error shall be returned. This flag shall prevent any
146 * type of name resolution service from being invoked.
147 * AI_V4MAPPED - If set, along with an ai_family of AF_INET6, then
148 * getaddrinfo() shall return IPv4-mapped IPv6 addresses
149 * on finding no matching IPv6 addresses ( ai_addrlen shall
150 * be 16). The AI_V4MAPPED flag shall be ignored unless
151 * ai_family equals AF_INET6.
152 * AI_ALL - If the AI_ALL flag is used with the AI_V4MAPPED flag,
153 * then getaddrinfo() shall return all matching IPv6 and
154 * IPv4 addresses. The AI_ALL flag without the AI_V4MAPPED
155 * flag is ignored.
156 * Output Parameters:
157 * res - upon successful return a pointer to a linked list of one
158 * or more addrinfo structures is returned through this
159 * argument. The caller can process each addrinfo structures
160 * in this list by following the ai_next pointer, until a
161 * NULL pointer is encountered. In each returned addrinfo
162 * structure the three members ai_family, ai_socktype, and
163 * ai_protocol are corresponding arguments for a call to the
164 * socket() function. In each addrinfo structure the ai_addr
165 * field points to filled-in socket address structure whose
166 * length is specified by the ai_addrlen member.
168 * Return Value:
169 * This function returns 0 upon success or a nonzero error code. The
170 * following names are nonzero error codes from getaddrinfo(), and are
171 * defined in <netdb.h>.
172 * EAI_ADDRFAMILY - address family not supported
173 * EAI_AGAIN - DNS temporary failure
174 * EAI_BADFLAGS - invalid ai_flags
175 * EAI_FAIL - DNS non-recoverable failure
176 * EAI_FAMILY - ai_family not supported
177 * EAI_MEMORY - memory allocation failure
178 * EAI_NODATA - no address associated with nodename
179 * EAI_NONAME - host/servname not known
180 * EAI_SERVICE - servname not supported for ai_socktype
181 * EAI_SOCKTYPE - ai_socktype not supported
182 * EAI_SYSTEM - system error in errno
184 * Memory Allocation:
185 * All of the information returned by getaddrinfo() is dynamically
186 * allocated: the addrinfo structures, and the socket address
187 * structures and canonical node name strings pointed to by the
188 * addrinfo structures.
192 static int
193 _getaddrinfo(const char *hostname, const char *servname,
194 const struct addrinfo *hints, struct addrinfo **res, int version)
196 struct addrinfo *cur;
197 struct addrinfo *aip;
198 struct addrinfo ai;
199 int error;
200 ushort_t port;
202 cur = &ai;
203 aip = &ai;
205 aip->ai_flags = 0;
206 aip->ai_family = PF_UNSPEC;
207 aip->ai_socktype = 0;
208 aip->ai_protocol = 0;
209 #ifdef __sparcv9
211 * We need to clear _ai_pad to preserve binary
212 * compatibility with previously compiled 64-bit
213 * applications by guaranteeing the upper 32-bits
214 * are empty.
216 aip->_ai_pad = 0;
217 #endif /* __sparcv9 */
218 aip->ai_addrlen = 0;
219 aip->ai_canonname = NULL;
220 aip->ai_addr = NULL;
221 aip->ai_next = NULL;
222 port = 0;
224 /* if nodename nor servname provided */
225 if (hostname == NULL && servname == NULL) {
226 *res = NULL;
227 return (EAI_NONAME);
229 if (hints != NULL) {
230 /* check for bad flags in hints */
231 if ((hints->ai_flags != 0) && (hints->ai_flags & ~AI_MASK)) {
232 *res = NULL;
233 return (EAI_BADFLAGS);
235 if ((hostname == NULL || *hostname == '\0') &&
236 (hints->ai_flags & AI_CANONNAME)) {
237 *res = NULL;
238 return (EAI_BADFLAGS);
240 if (hints->ai_family != PF_UNSPEC &&
241 hints->ai_family != PF_INET &&
242 hints->ai_family != PF_INET6) {
243 *res = NULL;
244 return (EAI_FAMILY);
247 (void) memcpy(aip, hints, sizeof (*aip));
248 #ifdef __sparcv9
250 * We need to clear _ai_pad to preserve binary
251 * compatibility. See prior comment.
253 aip->_ai_pad = 0;
254 #endif /* __sparcv9 */
255 switch (aip->ai_socktype) {
256 case ANY:
257 switch (aip->ai_protocol) {
258 case ANY:
259 break;
260 case IPPROTO_UDP:
261 aip->ai_socktype = SOCK_DGRAM;
262 break;
263 case IPPROTO_TCP:
264 case IPPROTO_SCTP:
265 aip->ai_socktype = SOCK_STREAM;
266 break;
267 default:
268 aip->ai_socktype = SOCK_RAW;
269 break;
271 break;
272 case SOCK_RAW:
273 break;
274 case SOCK_SEQPACKET:
276 * If the hint does not have a preference on the
277 * protocol, use SCTP as the default for
278 * SOCK_SEQPACKET.
280 if (aip->ai_protocol == ANY)
281 aip->ai_protocol = IPPROTO_SCTP;
282 break;
283 case SOCK_DGRAM:
284 aip->ai_protocol = IPPROTO_UDP;
285 break;
286 case SOCK_STREAM:
288 * If the hint does not have a preference on the
289 * protocol, use TCP as the default for SOCK_STREAM.
291 if (aip->ai_protocol == ANY)
292 aip->ai_protocol = IPPROTO_TCP;
293 break;
294 default:
295 *res = NULL;
296 return (EAI_SOCKTYPE);
301 * Get the service.
304 if (servname != NULL) {
305 struct servent result;
306 int bufsize = 128;
307 char *buf = NULL;
308 struct servent *sp;
309 char *proto = NULL;
311 switch (aip->ai_socktype) {
312 case ANY:
313 proto = NULL;
314 break;
315 case SOCK_DGRAM:
316 proto = "udp";
317 break;
318 case SOCK_STREAM:
320 * If there is no hint given, use TCP as the default
321 * protocol.
323 switch (aip->ai_protocol) {
324 case ANY:
325 case IPPROTO_TCP:
326 default:
327 proto = "tcp";
328 break;
329 case IPPROTO_SCTP:
330 proto = "sctp";
331 break;
333 break;
334 case SOCK_SEQPACKET:
335 /* Default to SCTP if no hint given. */
336 switch (aip->ai_protocol) {
337 case ANY:
338 default:
339 proto = "sctp";
340 break;
342 break;
345 * Servname string can be a decimal port number.
346 * If we already know the socket type there is no need
347 * to call getservbyport.
349 if (aip->ai_flags & AI_NUMERICSERV) {
350 if (!str_isnumber(servname)) {
351 return (EAI_NONAME);
353 port = htons(atoi(servname));
354 } else if (str_isnumber(servname)) {
355 port = htons(atoi(servname));
356 if (aip->ai_socktype == ANY) {
357 do {
358 if (buf != NULL)
359 free(buf);
360 bufsize *= 2;
361 buf = malloc(bufsize);
362 if (buf == NULL) {
363 *res = NULL;
364 return (EAI_MEMORY);
367 sp = getservbyport_r(port, proto,
368 &result, buf, bufsize);
369 if (sp == NULL && errno != ERANGE) {
370 free(buf);
371 *res = NULL;
372 return (EAI_SERVICE);
375 * errno == ERANGE so our scratch buffer space
376 * wasn't big enough. Double it and try
377 * again.
379 } while (sp == NULL);
381 } else {
382 do {
383 if (buf != NULL)
384 free(buf);
385 bufsize *= 2;
386 buf = malloc(bufsize);
387 if (buf == NULL) {
388 *res = NULL;
389 return (EAI_MEMORY);
392 sp = getservbyname_r(servname, proto, &result,
393 buf, bufsize);
394 if (sp == NULL && errno != ERANGE) {
395 free(buf);
396 *res = NULL;
397 return (EAI_SERVICE);
400 * errno == ERANGE so our scratch buffer space wasn't
401 * big enough. Double it and try again.
403 } while (sp == NULL);
405 port = sp->s_port;
407 if (aip->ai_socktype == ANY) {
408 if (aip->ai_flags & AI_NUMERICSERV) {
410 * RFC 2553bis doesn't allow us to use the
411 * any resolver to find out if there is a
412 * match. We could walk the service file
413 * with *servent(). Given the commonality of
414 * calling getaddrinfo() with a number and
415 * ANY protocol we won't add that at this time.
417 return (EAI_NONAME);
420 if (strcmp(sp->s_proto, "udp") == 0) {
421 aip->ai_socktype = SOCK_DGRAM;
422 aip->ai_protocol = IPPROTO_UDP;
423 } else if (strcmp(sp->s_proto, "tcp") == 0) {
424 aip->ai_socktype = SOCK_STREAM;
425 aip->ai_protocol = IPPROTO_TCP;
426 } else if (strcmp(sp->s_proto, "sctp") == 0) {
427 aip->ai_socktype = SOCK_STREAM;
428 aip->ai_protocol = IPPROTO_SCTP;
429 } else {
430 if (buf != NULL)
431 free(buf);
433 *res = NULL;
434 errno = EPROTONOSUPPORT;
435 return (EAI_SYSTEM);
439 if (buf != NULL)
440 free(buf);
444 * hostname is NULL
445 * case 1: AI_PASSIVE bit set : anyaddr 0.0.0.0 or ::
446 * case 2: AI_PASSIVE bit not set : localhost 127.0.0.1 or ::1
449 if (hostname == NULL) {
450 struct addrinfo *nai;
451 socklen_t addrlen;
452 char *canonname;
454 if (aip->ai_family == PF_INET)
455 goto v4only;
456 /* create IPv6 addrinfo */
457 nai = malloc(sizeof (struct addrinfo));
458 if (nai == NULL)
459 goto nomem;
460 *nai = *aip;
461 addrlen = sizeof (struct sockaddr_in6);
462 nai->ai_addr = malloc(addrlen);
463 if (nai->ai_addr == NULL) {
464 freeaddrinfo(nai);
465 goto nomem;
467 bzero(nai->ai_addr, addrlen);
468 nai->ai_addrlen = addrlen;
469 nai->ai_family = PF_INET6;
470 nai->ai_canonname = NULL;
471 if (nai->ai_flags & AI_PASSIVE) {
472 ai2sin6(nai)->sin6_addr = in6addr_any;
473 } else {
474 ai2sin6(nai)->sin6_addr = in6addr_loopback;
475 if (nai->ai_flags & AI_CANONNAME) {
476 canonname = strdup("loopback");
477 if (canonname == NULL) {
478 freeaddrinfo(nai);
479 goto nomem;
481 nai->ai_canonname = canonname;
484 ai2sin6(nai)->sin6_family = PF_INET6;
485 ai2sin6(nai)->sin6_port = port;
486 cur->ai_next = nai;
487 cur = nai;
488 if (aip->ai_family == PF_INET6) {
489 cur->ai_next = NULL;
490 goto success;
492 /* If address family is PF_UNSPEC or PF_INET */
493 v4only:
494 /* create IPv4 addrinfo */
495 nai = malloc(sizeof (struct addrinfo));
496 if (nai == NULL)
497 goto nomem;
498 *nai = *aip;
499 addrlen = sizeof (struct sockaddr_in);
500 nai->ai_addr = malloc(addrlen);
501 if (nai->ai_addr == NULL) {
502 freeaddrinfo(nai);
503 goto nomem;
505 bzero(nai->ai_addr, addrlen);
506 nai->ai_addrlen = addrlen;
507 nai->ai_family = PF_INET;
508 nai->ai_canonname = NULL;
509 if (nai->ai_flags & AI_PASSIVE) {
510 ai2sin(nai)->sin_addr.s_addr = INADDR_ANY;
511 } else {
512 ai2sin(nai)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
513 if (nai->ai_flags & AI_CANONNAME &&
514 nai->ai_family != PF_UNSPEC) {
515 canonname = strdup("loopback");
516 if (canonname == NULL) {
517 freeaddrinfo(nai);
518 goto nomem;
520 nai->ai_canonname = canonname;
523 ai2sin(nai)->sin_family = PF_INET;
524 ai2sin(nai)->sin_port = port;
525 cur->ai_next = nai;
526 cur = nai;
527 cur->ai_next = NULL;
528 goto success;
531 /* hostname string is a literal address or an alphabetical name */
532 error = get_addr(aip->ai_family, hostname, aip, cur, port, version);
533 if (error) {
534 *res = NULL;
535 return (error);
538 success:
539 *res = aip->ai_next;
540 return (0);
542 nomem:
543 return (EAI_MEMORY);
547 getaddrinfo(const char *hostname, const char *servname,
548 const struct addrinfo *hints, struct addrinfo **res)
550 return (_getaddrinfo(hostname, servname, hints, res, GAIV_DEFAULT));
554 __xnet_getaddrinfo(const char *hostname, const char *servname,
555 const struct addrinfo *hints, struct addrinfo **res)
557 return (_getaddrinfo(hostname, servname, hints, res, GAIV_XPG6));
560 static int
561 get_addr(int family, const char *hostname, struct addrinfo *aip, struct
562 addrinfo *cur, ushort_t port, int version)
564 struct hostent *hp;
565 char _hostname[MAXHOSTNAMELEN];
566 int i, errnum;
567 struct addrinfo *nai;
568 int addrlen;
569 char *canonname;
570 boolean_t firsttime = B_TRUE;
571 boolean_t create_v6_addrinfo;
572 struct in_addr v4addr;
573 struct in6_addr v6addr;
574 struct in6_addr *v6addrp;
575 char *zonestr = NULL;
578 * Check for existence of address-zoneid delimiter '%'
579 * If the delimiter exists, parse the zoneid portion of
580 * <addr>%<zone_id>
582 if ((zonestr = strchr(hostname, '%')) != NULL) {
583 /* make sure we have room for <addr> portion of hostname */
584 if (((zonestr - hostname) + 1) > sizeof (_hostname)) {
585 return (EAI_MEMORY);
588 /* chop off and save <zone_id> portion */
589 (void) strlcpy(_hostname, hostname, (zonestr - hostname) + 1);
590 ++zonestr; /* make zonestr point at start of <zone-id> */
591 /* ensure zone is valid */
592 if ((*zonestr == '\0') || (strlen(zonestr) > LIFNAMSIZ)) {
593 return (EAI_NONAME);
595 } else {
596 size_t hlen = sizeof (_hostname);
598 if (strlcpy(_hostname, hostname, hlen) >= hlen) {
599 return (EAI_MEMORY);
603 /* Check to see if AI_NUMERICHOST bit is set */
604 if (aip->ai_flags & AI_NUMERICHOST) {
605 /* check to see if _hostname points to a literal IP address */
606 if (!((inet_addr(_hostname) != ((in_addr_t)-1)) ||
607 (strcmp(_hostname, HOST_BROADCAST) == 0) ||
608 (inet_pton(AF_INET6, _hostname, &v6addr) > 0))) {
609 return (EAI_NONAME);
613 /* if hostname argument is literal, name service doesn't get called */
614 if (family == PF_UNSPEC) {
615 hp = getipnodebyname(_hostname, AF_INET6, AI_ALL |
616 aip->ai_flags | AI_V4MAPPED | AI_ADDRINFO, &errnum);
617 } else {
618 hp = getipnodebyname(_hostname, family, aip->ai_flags, &errnum);
621 if (hp == NULL) {
622 switch (errnum) {
623 case HOST_NOT_FOUND:
624 return (EAI_NONAME);
625 case TRY_AGAIN:
626 return (EAI_AGAIN);
627 case NO_RECOVERY:
628 return (EAI_FAIL);
629 case NO_ADDRESS:
630 if (version == GAIV_XPG6)
631 return (EAI_NONAME);
632 return (EAI_NODATA);
633 default:
634 return (EAI_SYSTEM);
638 for (i = 0; hp->h_addr_list[i]; i++) {
639 /* Determine if an IPv6 addrinfo structure should be created */
640 create_v6_addrinfo = B_TRUE;
641 if (hp->h_addrtype == AF_INET6) {
642 v6addrp = (struct in6_addr *)hp->h_addr_list[i];
643 if (!(aip->ai_flags & AI_V4MAPPED) &&
644 IN6_IS_ADDR_V4MAPPED(v6addrp)) {
645 create_v6_addrinfo = B_FALSE;
646 IN6_V4MAPPED_TO_INADDR(v6addrp, &v4addr);
648 } else if (hp->h_addrtype == AF_INET) {
649 create_v6_addrinfo = B_FALSE;
650 (void) memcpy(&v4addr, hp->h_addr_list[i],
651 sizeof (struct in_addr));
652 } else {
653 return (EAI_SYSTEM);
656 if (create_v6_addrinfo) {
657 /* create IPv6 addrinfo */
658 nai = malloc(sizeof (struct addrinfo));
659 if (nai == NULL)
660 goto nomem;
661 *nai = *aip;
662 addrlen = sizeof (struct sockaddr_in6);
663 nai->ai_addr = malloc(addrlen);
664 if (nai->ai_addr == NULL) {
665 freeaddrinfo(nai);
666 goto nomem;
668 bzero(nai->ai_addr, addrlen);
669 nai->ai_addrlen = addrlen;
670 nai->ai_family = PF_INET6;
672 (void) memcpy(ai2sin6(nai)->sin6_addr.s6_addr,
673 hp->h_addr_list[i], sizeof (struct in6_addr));
674 nai->ai_canonname = NULL;
675 if ((nai->ai_flags & AI_CANONNAME) && firsttime) {
676 canonname = strdup(hp->h_name);
677 if (canonname == NULL) {
678 freeaddrinfo(nai);
679 goto nomem;
681 nai->ai_canonname = canonname;
682 firsttime = B_FALSE;
684 ai2sin6(nai)->sin6_family = PF_INET6;
685 ai2sin6(nai)->sin6_port = port;
686 /* set sin6_scope_id */
687 if (zonestr != NULL) {
689 * Translate 'zonestr' into a valid
690 * sin6_scope_id.
692 if ((errnum =
693 getscopeidfromzone(ai2sin6(nai), zonestr,
694 &ai2sin6(nai)->sin6_scope_id)) != 0) {
695 return (errnum);
697 } else {
698 ai2sin6(nai)->sin6_scope_id = 0;
700 } else {
701 /* create IPv4 addrinfo */
702 nai = malloc(sizeof (struct addrinfo));
703 if (nai == NULL)
704 goto nomem;
705 *nai = *aip;
706 addrlen = sizeof (struct sockaddr_in);
707 nai->ai_addr = malloc(addrlen);
708 if (nai->ai_addr == NULL) {
709 freeaddrinfo(nai);
710 goto nomem;
712 bzero(nai->ai_addr, addrlen);
713 nai->ai_addrlen = addrlen;
714 nai->ai_family = PF_INET;
715 (void) memcpy(&(ai2sin(nai)->sin_addr.s_addr),
716 &v4addr, sizeof (struct in_addr));
717 nai->ai_canonname = NULL;
718 if (nai->ai_flags & AI_CANONNAME && firsttime) {
719 canonname = strdup(hp->h_name);
720 if (canonname == NULL) {
721 freeaddrinfo(nai);
722 goto nomem;
724 nai->ai_canonname = canonname;
725 firsttime = B_FALSE;
727 ai2sin(nai)->sin_family = PF_INET;
728 ai2sin(nai)->sin_port = port;
731 cur->ai_next = nai;
732 cur = nai;
734 cur->ai_next = NULL;
735 freehostent(hp);
736 return (0);
738 nomem:
739 freehostent(hp);
740 return (EAI_MEMORY);
745 * getscopeidfromzone(sa, zone, sin6_scope_id)
747 * Converts the string pointed to by 'zone' into a sin6_scope_id.
748 * 'zone' will either be a pointer to an interface name or will
749 * be a literal sin6_scope_id.
751 * 0 is returned on success and the output parameter 'sin6_scope_id' will
752 * be set to a valid sin6_scope_id.
753 * EAI_NONAME is returned for either of two reasons:
754 * 1. The IPv6 address pointed to by sa->sin6_addr is not
755 * part of the 'link scope' (ie link local, nodelocal multicast or
756 * linklocal multicast address)
757 * 2. The string pointed to by 'zone' can not be translate to a valid
758 * sin6_scope_id.
760 static uint_t
761 getscopeidfromzone(const struct sockaddr_in6 *sa, const char *zone,
762 uint32_t *sin6_scope_id) {
763 const in6_addr_t *addr = &sa->sin6_addr;
764 ulong_t ul_scope_id;
765 char *endp;
767 if (IN6_IS_ADDR_LINKSCOPE(addr)) {
769 * Look up interface index associated with interface name
770 * pointed to by 'zone'. Since the address is part of the link
771 * scope, there is a one-to-one relationship between interface
772 * index and sin6_scope_id.
773 * If an interface index can not be found for 'zone', then
774 * treat 'zone' as a literal sin6_scope_id value.
776 if ((*sin6_scope_id = if_nametoindex(zone)) != 0) {
777 return (0);
778 } else {
779 if ((ul_scope_id = strtoul(zone, &endp, 10)) != 0) {
780 /* check that entire string was read */
781 if (*endp != '\0') {
782 return (EAI_NONAME);
784 *sin6_scope_id =
785 (uint32_t)(ul_scope_id & 0xffffffffUL);
786 } else {
787 return (EAI_NONAME);
790 } else {
791 return (EAI_NONAME);
793 return (0);
797 void
798 freeaddrinfo(struct addrinfo *ai)
800 struct addrinfo *next;
802 do {
803 next = ai->ai_next;
804 if (ai->ai_canonname)
805 free(ai->ai_canonname);
806 if (ai->ai_addr)
807 free(ai->ai_addr);
808 free(ai);
809 ai = next;
810 } while (ai != NULL);
813 static boolean_t
814 str_isnumber(const char *p)
816 char *q = (char *)p;
817 while (*q) {
818 if (!isdigit(*q))
819 return (B_FALSE);
820 q++;
822 return (B_TRUE);
824 static const char *gai_errlist[] = {
825 "name translation error 0 (no error)", /* 0 */
826 "specified address family not supported", /* 1 EAI_ADDRFAMILY */
827 "temporary name resolution failure", /* 2 EAI_AGAIN */
828 "invalid flags", /* 3 EAI_BADFLAGS */
829 "non-recoverable name resolution failure", /* 4 EAI_FAIL */
830 "specified address family not supported", /* 5 EAI_FAMILY */
831 "memory allocation failure", /* 6 EAI_MEMORY */
832 "no address for the specified node name", /* 7 EAI_NODATA */
833 "node name or service name not known", /* 8 EAI_NONAME */
834 "service name not available for the specified socket type",
835 /* 9 EAI_SERVICE */
836 "specified socket type not supported", /* 10 EAI_SOCKTYPE */
837 "system error", /* 11 EAI_SYSTEM */
839 static int gai_nerr = { sizeof (gai_errlist)/sizeof (gai_errlist[0]) };
841 const char *
842 gai_strerror(int ecode)
844 if (ecode < 0)
845 return (dgettext(TEXT_DOMAIN,
846 "name translation internal error"));
847 else if (ecode < gai_nerr)
848 return (dgettext(TEXT_DOMAIN, gai_errlist[ecode]));
849 return (dgettext(TEXT_DOMAIN, "unknown name translation error"));