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