Home | History | Annotate | Download | only in inet
      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