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