xref: /titanic_44/usr/src/lib/libsocket/inet/getnameinfo.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate 
23*7c478bd9Sstevel@tonic-gate /*
24*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
25*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
26*7c478bd9Sstevel@tonic-gate  */
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
31*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
32*7c478bd9Sstevel@tonic-gate #include <string.h>
33*7c478bd9Sstevel@tonic-gate #include <strings.h>
34*7c478bd9Sstevel@tonic-gate #include <stdio.h>
35*7c478bd9Sstevel@tonic-gate #include <ctype.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
37*7c478bd9Sstevel@tonic-gate #include <netdb.h>
38*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
39*7c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
40*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
42*7c478bd9Sstevel@tonic-gate #include <net/if.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #define	sa2sin(x)	((struct sockaddr_in *)(x))
45*7c478bd9Sstevel@tonic-gate #define	sa2sin6(x)	((struct sockaddr_in6 *)(x))
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #define	NI_MASK	(NI_NOFQDN | NI_NUMERICHOST | NI_NAMEREQD | NI_NUMERICSERV | \
48*7c478bd9Sstevel@tonic-gate     NI_DGRAM | NI_WITHSCOPEID)
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate static int addzoneid(const struct sockaddr_in6 *sa, char *host,
51*7c478bd9Sstevel@tonic-gate     size_t hostlen);
52*7c478bd9Sstevel@tonic-gate static size_t getzonestr(const struct sockaddr_in6 *sa, char *zonestr,
53*7c478bd9Sstevel@tonic-gate     size_t zonelen);
54*7c478bd9Sstevel@tonic-gate static const char *_inet_ntop_native();
55*7c478bd9Sstevel@tonic-gate /*
56*7c478bd9Sstevel@tonic-gate  * getnameinfo:
57*7c478bd9Sstevel@tonic-gate  *
58*7c478bd9Sstevel@tonic-gate  * Purpose:
59*7c478bd9Sstevel@tonic-gate  *   Routine for performing Address-to-nodename in a
60*7c478bd9Sstevel@tonic-gate  *   protocol-independent fashion.
61*7c478bd9Sstevel@tonic-gate  * Description:
62*7c478bd9Sstevel@tonic-gate  *   This function looks up an IP address and port number provided
63*7c478bd9Sstevel@tonic-gate  *   by the caller in the name service database and returns the nodename
64*7c478bd9Sstevel@tonic-gate  *   and servname respectively in the buffers provided by the caller.
65*7c478bd9Sstevel@tonic-gate  * Input Parameters:
66*7c478bd9Sstevel@tonic-gate  *   sa      - points to either a sockaddr_in structure (for
67*7c478bd9Sstevel@tonic-gate  *             IPv4) or a sockaddr_in6 structure (for IPv6).
68*7c478bd9Sstevel@tonic-gate  *   salen   - length of the sockaddr_in or sockaddr_in6 structure.
69*7c478bd9Sstevel@tonic-gate  *   hostlen - length of caller supplied "host" buffer
70*7c478bd9Sstevel@tonic-gate  *   servlen - length of caller supplied "serv" buffer
71*7c478bd9Sstevel@tonic-gate  *   flags   - changes default actions based on setting.
72*7c478bd9Sstevel@tonic-gate  *       Possible settings for "flags":
73*7c478bd9Sstevel@tonic-gate  *       NI_NOFQDN - Always return nodename portion of the fully-qualified
74*7c478bd9Sstevel@tonic-gate  *                   domain name (FQDN).
75*7c478bd9Sstevel@tonic-gate  *       NI_NUMERICHOST - Always return numeric form of the host's
76*7c478bd9Sstevel@tonic-gate  *			  address.
77*7c478bd9Sstevel@tonic-gate  *       NI_NAMEREQD - If hostname cannot be located in database,
78*7c478bd9Sstevel@tonic-gate  *                     don't return numeric form of address - return
79*7c478bd9Sstevel@tonic-gate  *                     an error instead.
80*7c478bd9Sstevel@tonic-gate  *       NI_NUMERICSERV - Always return numeric form of the service address
81*7c478bd9Sstevel@tonic-gate  *                        instead of its name.
82*7c478bd9Sstevel@tonic-gate  *       NI_DGRAM - Specifies that the service is a datagram service, and
83*7c478bd9Sstevel@tonic-gate  *                  causes getservbyport() to be called with a second
84*7c478bd9Sstevel@tonic-gate  *                  argument of "udp" instead of its default "tcp".
85*7c478bd9Sstevel@tonic-gate  * Output Parameters:
86*7c478bd9Sstevel@tonic-gate  *   host - return the nodename associcated with the IP address in the
87*7c478bd9Sstevel@tonic-gate  *          buffer pointed to by the "host" argument.
88*7c478bd9Sstevel@tonic-gate  *   serv - return the service name associated with the port number
89*7c478bd9Sstevel@tonic-gate  *          in the buffer pointed to by the "serv" argument.
90*7c478bd9Sstevel@tonic-gate  * Return Value:
91*7c478bd9Sstevel@tonic-gate  *   This function indicates successful completion by a zero return
92*7c478bd9Sstevel@tonic-gate  *   value; a non-zero return value indicates failure.
93*7c478bd9Sstevel@tonic-gate  */
94*7c478bd9Sstevel@tonic-gate int
getnameinfo(const struct sockaddr * sa,socklen_t salen,char * host,socklen_t hostlen,char * serv,socklen_t servlen,int flags)95*7c478bd9Sstevel@tonic-gate getnameinfo(const struct sockaddr *sa, socklen_t salen,
96*7c478bd9Sstevel@tonic-gate 	    char *host, socklen_t hostlen,
97*7c478bd9Sstevel@tonic-gate 	    char *serv, socklen_t servlen, int flags)
98*7c478bd9Sstevel@tonic-gate {
99*7c478bd9Sstevel@tonic-gate 	char		*addr;
100*7c478bd9Sstevel@tonic-gate 	size_t		alen, slen;
101*7c478bd9Sstevel@tonic-gate 	in_port_t	port;
102*7c478bd9Sstevel@tonic-gate 	int		errnum;
103*7c478bd9Sstevel@tonic-gate 	int		err;
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	/* Verify correctness of buffer lengths */
106*7c478bd9Sstevel@tonic-gate 	if ((hostlen == 0) && (servlen == 0))
107*7c478bd9Sstevel@tonic-gate 		return (EAI_FAIL);
108*7c478bd9Sstevel@tonic-gate 	/* Verify correctness of possible flag settings */
109*7c478bd9Sstevel@tonic-gate 	if ((flags != 0) && (flags & ~NI_MASK))
110*7c478bd9Sstevel@tonic-gate 		return (EAI_BADFLAGS);
111*7c478bd9Sstevel@tonic-gate 	if (sa == NULL)
112*7c478bd9Sstevel@tonic-gate 		return (EAI_ADDRFAMILY);
113*7c478bd9Sstevel@tonic-gate 	switch (sa->sa_family) {
114*7c478bd9Sstevel@tonic-gate 	case AF_INET:
115*7c478bd9Sstevel@tonic-gate 		addr = (char *)&sa2sin(sa)->sin_addr;
116*7c478bd9Sstevel@tonic-gate 		alen = sizeof (struct in_addr);
117*7c478bd9Sstevel@tonic-gate 		slen = sizeof (struct sockaddr_in);
118*7c478bd9Sstevel@tonic-gate 		port = (sa2sin(sa)->sin_port); /* network byte order */
119*7c478bd9Sstevel@tonic-gate 		break;
120*7c478bd9Sstevel@tonic-gate 	case AF_INET6:
121*7c478bd9Sstevel@tonic-gate 		addr = (char *)&sa2sin6(sa)->sin6_addr;
122*7c478bd9Sstevel@tonic-gate 		alen = sizeof (struct in6_addr);
123*7c478bd9Sstevel@tonic-gate 		slen = sizeof (struct sockaddr_in6);
124*7c478bd9Sstevel@tonic-gate 		port = (sa2sin6(sa)->sin6_port); /* network byte order */
125*7c478bd9Sstevel@tonic-gate 		break;
126*7c478bd9Sstevel@tonic-gate 	default:
127*7c478bd9Sstevel@tonic-gate 		return (EAI_FAMILY);
128*7c478bd9Sstevel@tonic-gate 	}
129*7c478bd9Sstevel@tonic-gate 	if (salen != slen)
130*7c478bd9Sstevel@tonic-gate 		return (EAI_FAIL);
131*7c478bd9Sstevel@tonic-gate 	/*
132*7c478bd9Sstevel@tonic-gate 	 * Case 1: if Caller sets hostlen != 0, then
133*7c478bd9Sstevel@tonic-gate 	 * fill in "host" buffer that user passed in
134*7c478bd9Sstevel@tonic-gate 	 * with appropriate text string.
135*7c478bd9Sstevel@tonic-gate 	 */
136*7c478bd9Sstevel@tonic-gate 	if (hostlen != 0) {
137*7c478bd9Sstevel@tonic-gate 		if (flags & NI_NUMERICHOST) {
138*7c478bd9Sstevel@tonic-gate 			/* Caller wants the host's numeric address */
139*7c478bd9Sstevel@tonic-gate 			if (inet_ntop(sa->sa_family, addr,
140*7c478bd9Sstevel@tonic-gate 			    host, hostlen) == NULL)
141*7c478bd9Sstevel@tonic-gate 				return (EAI_SYSTEM);
142*7c478bd9Sstevel@tonic-gate 		} else {
143*7c478bd9Sstevel@tonic-gate 			struct hostent	*hp;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 			/* Caller wants the name of host */
146*7c478bd9Sstevel@tonic-gate 			hp = getipnodebyaddr(addr, alen, sa->sa_family,
147*7c478bd9Sstevel@tonic-gate 			    &errnum);
148*7c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
149*7c478bd9Sstevel@tonic-gate 				if (flags & NI_NOFQDN) {
150*7c478bd9Sstevel@tonic-gate 					char *dot;
151*7c478bd9Sstevel@tonic-gate 					/*
152*7c478bd9Sstevel@tonic-gate 					 * Caller doesn't want fully-qualified
153*7c478bd9Sstevel@tonic-gate 					 * name.
154*7c478bd9Sstevel@tonic-gate 					 */
155*7c478bd9Sstevel@tonic-gate 					dot = strchr(hp->h_name, '.');
156*7c478bd9Sstevel@tonic-gate 					if (dot != NULL)
157*7c478bd9Sstevel@tonic-gate 						*dot = '\0';
158*7c478bd9Sstevel@tonic-gate 				}
159*7c478bd9Sstevel@tonic-gate 				if (strlen(hp->h_name) + 1 > hostlen) {
160*7c478bd9Sstevel@tonic-gate 					freehostent(hp);
161*7c478bd9Sstevel@tonic-gate 					return (EAI_OVERFLOW);
162*7c478bd9Sstevel@tonic-gate 				}
163*7c478bd9Sstevel@tonic-gate 				(void) strcpy(host, hp->h_name);
164*7c478bd9Sstevel@tonic-gate 				freehostent(hp);
165*7c478bd9Sstevel@tonic-gate 			} else {
166*7c478bd9Sstevel@tonic-gate 				/*
167*7c478bd9Sstevel@tonic-gate 				 * Host's name cannot be located in the name
168*7c478bd9Sstevel@tonic-gate 				 * service database. If NI_NAMEREQD is set,
169*7c478bd9Sstevel@tonic-gate 				 * return error; otherwise, return host's
170*7c478bd9Sstevel@tonic-gate 				 * numeric address.
171*7c478bd9Sstevel@tonic-gate 				 */
172*7c478bd9Sstevel@tonic-gate 				if (flags & NI_NAMEREQD) {
173*7c478bd9Sstevel@tonic-gate 					switch (errnum) {
174*7c478bd9Sstevel@tonic-gate 					case HOST_NOT_FOUND:
175*7c478bd9Sstevel@tonic-gate 						return (EAI_NONAME);
176*7c478bd9Sstevel@tonic-gate 					case TRY_AGAIN:
177*7c478bd9Sstevel@tonic-gate 						return (EAI_AGAIN);
178*7c478bd9Sstevel@tonic-gate 					case NO_RECOVERY:
179*7c478bd9Sstevel@tonic-gate 						return (EAI_FAIL);
180*7c478bd9Sstevel@tonic-gate 					case NO_ADDRESS:
181*7c478bd9Sstevel@tonic-gate 						return (EAI_NODATA);
182*7c478bd9Sstevel@tonic-gate 					default:
183*7c478bd9Sstevel@tonic-gate 						return (EAI_SYSTEM);
184*7c478bd9Sstevel@tonic-gate 					}
185*7c478bd9Sstevel@tonic-gate 				}
186*7c478bd9Sstevel@tonic-gate 				if (_inet_ntop_native(sa->sa_family, addr,
187*7c478bd9Sstevel@tonic-gate 				    host, hostlen) == NULL)
188*7c478bd9Sstevel@tonic-gate 					return (EAI_SYSTEM);
189*7c478bd9Sstevel@tonic-gate 			}
190*7c478bd9Sstevel@tonic-gate 		}
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 		/*
193*7c478bd9Sstevel@tonic-gate 		 * Check for a non-zero sin6_scope_id, indicating a
194*7c478bd9Sstevel@tonic-gate 		 * zone-id needs to be appended to the resultant 'host'
195*7c478bd9Sstevel@tonic-gate 		 * string.
196*7c478bd9Sstevel@tonic-gate 		 */
197*7c478bd9Sstevel@tonic-gate 		if ((sa->sa_family == AF_INET6) &&
198*7c478bd9Sstevel@tonic-gate 		    (sa2sin6(sa)->sin6_scope_id != 0)) {
199*7c478bd9Sstevel@tonic-gate 			/*
200*7c478bd9Sstevel@tonic-gate 			 * According to draft-ietf-ipngwg-scoping-arch-XX, only
201*7c478bd9Sstevel@tonic-gate 			 * non-global scope addresses can make use of the
202*7c478bd9Sstevel@tonic-gate 			 * <addr>%<zoneid> format.  This implemenation
203*7c478bd9Sstevel@tonic-gate 			 * supports only link scope addresses, since the use of
204*7c478bd9Sstevel@tonic-gate 			 * site-local addressing is not yet fully specified.
205*7c478bd9Sstevel@tonic-gate 			 * If the address meets this criteria, attempt to add a
206*7c478bd9Sstevel@tonic-gate 			 * zone-id to 'host'.  If it does not, return
207*7c478bd9Sstevel@tonic-gate 			 * EAI_NONAME.
208*7c478bd9Sstevel@tonic-gate 			 */
209*7c478bd9Sstevel@tonic-gate 			if (IN6_IS_ADDR_LINKSCOPE(&(sa2sin6(sa)->sin6_addr))) {
210*7c478bd9Sstevel@tonic-gate 				if ((err = addzoneid(sa2sin6(sa), host,
211*7c478bd9Sstevel@tonic-gate 				    hostlen)) != 0) {
212*7c478bd9Sstevel@tonic-gate 					return (err);
213*7c478bd9Sstevel@tonic-gate 				}
214*7c478bd9Sstevel@tonic-gate 			} else {
215*7c478bd9Sstevel@tonic-gate 				return (EAI_NONAME);
216*7c478bd9Sstevel@tonic-gate 			}
217*7c478bd9Sstevel@tonic-gate 		}
218*7c478bd9Sstevel@tonic-gate 	}
219*7c478bd9Sstevel@tonic-gate 	/*
220*7c478bd9Sstevel@tonic-gate 	 * Case 2: if Caller sets servlen != 0, then
221*7c478bd9Sstevel@tonic-gate 	 * fill in "serv" buffer that user passed in
222*7c478bd9Sstevel@tonic-gate 	 * with appropriate text string.
223*7c478bd9Sstevel@tonic-gate 	 */
224*7c478bd9Sstevel@tonic-gate 	if (servlen != 0) {
225*7c478bd9Sstevel@tonic-gate 		char port_buf[10];
226*7c478bd9Sstevel@tonic-gate 		int portlen;
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 		if (flags & NI_NUMERICSERV) {
229*7c478bd9Sstevel@tonic-gate 			/* Caller wants the textual form of the port number */
230*7c478bd9Sstevel@tonic-gate 			portlen = snprintf(port_buf, sizeof (port_buf), "%hu",
231*7c478bd9Sstevel@tonic-gate 			    ntohs(port));
232*7c478bd9Sstevel@tonic-gate 			if (servlen < portlen + 1)
233*7c478bd9Sstevel@tonic-gate 				return (EAI_OVERFLOW);
234*7c478bd9Sstevel@tonic-gate 			(void) strcpy(serv, port_buf);
235*7c478bd9Sstevel@tonic-gate 		} else {
236*7c478bd9Sstevel@tonic-gate 			struct servent	*sp;
237*7c478bd9Sstevel@tonic-gate 			/*
238*7c478bd9Sstevel@tonic-gate 			 * Caller wants the name of the service.
239*7c478bd9Sstevel@tonic-gate 			 * If NI_DGRAM is set, get service name for
240*7c478bd9Sstevel@tonic-gate 			 * specified port for udp.
241*7c478bd9Sstevel@tonic-gate 			 */
242*7c478bd9Sstevel@tonic-gate 			sp = getservbyport(port,
243*7c478bd9Sstevel@tonic-gate 				flags & NI_DGRAM ? "udp" : "tcp");
244*7c478bd9Sstevel@tonic-gate 			if (sp != NULL) {
245*7c478bd9Sstevel@tonic-gate 				if (servlen < strlen(sp->s_name) + 1)
246*7c478bd9Sstevel@tonic-gate 					return (EAI_OVERFLOW);
247*7c478bd9Sstevel@tonic-gate 				(void) strcpy(serv, sp->s_name);
248*7c478bd9Sstevel@tonic-gate 			} else {
249*7c478bd9Sstevel@tonic-gate 				/*
250*7c478bd9Sstevel@tonic-gate 				 * if service is not in the name server's
251*7c478bd9Sstevel@tonic-gate 				 * database, fill buffer with numeric form for
252*7c478bd9Sstevel@tonic-gate 				 * port number.
253*7c478bd9Sstevel@tonic-gate 				 */
254*7c478bd9Sstevel@tonic-gate 				portlen = snprintf(port_buf, sizeof (port_buf),
255*7c478bd9Sstevel@tonic-gate 				    "%hu", ntohs(port));
256*7c478bd9Sstevel@tonic-gate 				if (servlen < portlen + 1)
257*7c478bd9Sstevel@tonic-gate 					return (EAI_OVERFLOW);
258*7c478bd9Sstevel@tonic-gate 				(void) strcpy(serv, port_buf);
259*7c478bd9Sstevel@tonic-gate 			}
260*7c478bd9Sstevel@tonic-gate 		}
261*7c478bd9Sstevel@tonic-gate 	}
262*7c478bd9Sstevel@tonic-gate 	return (0);
263*7c478bd9Sstevel@tonic-gate }
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate /*
266*7c478bd9Sstevel@tonic-gate  * addzoneid(sa, host, hostlen)
267*7c478bd9Sstevel@tonic-gate  *
268*7c478bd9Sstevel@tonic-gate  * Appends a zone-id to the input 'host' string if the input sin6_scope_id
269*7c478bd9Sstevel@tonic-gate  * is non-zero.  The resultant 'host' string would be of the form
270*7c478bd9Sstevel@tonic-gate  * 'host'%'zone-id'.  Where 'zone-id' can be either an interface name or a
271*7c478bd9Sstevel@tonic-gate  * literal interface index.
272*7c478bd9Sstevel@tonic-gate  *
273*7c478bd9Sstevel@tonic-gate  * Return Values:
274*7c478bd9Sstevel@tonic-gate  * 0 - on success
275*7c478bd9Sstevel@tonic-gate  * EAI_MEMORY - an error occured when forming the output string
276*7c478bd9Sstevel@tonic-gate  */
277*7c478bd9Sstevel@tonic-gate static int
addzoneid(const struct sockaddr_in6 * sa,char * host,size_t hostlen)278*7c478bd9Sstevel@tonic-gate addzoneid(const struct sockaddr_in6 *sa, char *host, size_t hostlen)
279*7c478bd9Sstevel@tonic-gate {
280*7c478bd9Sstevel@tonic-gate 	char zonestr[LIFNAMSIZ];
281*7c478bd9Sstevel@tonic-gate 	size_t zonelen;
282*7c478bd9Sstevel@tonic-gate 	size_t addrlen = strlen(host);
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	/* make sure zonelen is valid sizeof (<addr>%<zoneid>\0) */
285*7c478bd9Sstevel@tonic-gate 	if (((zonelen = getzonestr(sa, zonestr, sizeof (zonestr))) == 0) ||
286*7c478bd9Sstevel@tonic-gate 	    ((addrlen + 1 + zonelen + 1) > hostlen)) {
287*7c478bd9Sstevel@tonic-gate 		return (EAI_MEMORY);
288*7c478bd9Sstevel@tonic-gate 	}
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	/* Create address string of form <addr>%<zoneid> */
291*7c478bd9Sstevel@tonic-gate 	host[addrlen] = '%'; /* place address-zoneid delimiter */
292*7c478bd9Sstevel@tonic-gate 	(void) strlcpy((host + addrlen + 1), zonestr, (zonelen + 1));
293*7c478bd9Sstevel@tonic-gate 	return (0);
294*7c478bd9Sstevel@tonic-gate }
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate /*
297*7c478bd9Sstevel@tonic-gate  * getzonestr(sa, zonestr)
298*7c478bd9Sstevel@tonic-gate  *
299*7c478bd9Sstevel@tonic-gate  * parse zone string from input sockaddr_in6
300*7c478bd9Sstevel@tonic-gate  *
301*7c478bd9Sstevel@tonic-gate  * Note:  This function calls if_indextoname, a very poor interface,
302*7c478bd9Sstevel@tonic-gate  *        defined in RFC2553, for converting an interface index to an
303*7c478bd9Sstevel@tonic-gate  *        interface name.  Callers of this function must be sure that
304*7c478bd9Sstevel@tonic-gate  *        zonestr is atleast LIFNAMSIZ in length, since this is the longest
305*7c478bd9Sstevel@tonic-gate  *        possible value if_indextoname will return.
306*7c478bd9Sstevel@tonic-gate  *
307*7c478bd9Sstevel@tonic-gate  * Return values:
308*7c478bd9Sstevel@tonic-gate  * 0 an error with calling this function occured
309*7c478bd9Sstevel@tonic-gate  * >0 zonestr is filled with a valid zoneid string and the return value is the
310*7c478bd9Sstevel@tonic-gate  *    length of that string.
311*7c478bd9Sstevel@tonic-gate  */
312*7c478bd9Sstevel@tonic-gate static size_t
getzonestr(const struct sockaddr_in6 * sa,char * zonestr,size_t zonelen)313*7c478bd9Sstevel@tonic-gate getzonestr(const struct sockaddr_in6 *sa, char *zonestr, size_t zonelen)
314*7c478bd9Sstevel@tonic-gate {
315*7c478bd9Sstevel@tonic-gate 	const in6_addr_t *addr;
316*7c478bd9Sstevel@tonic-gate 	uint32_t ifindex;
317*7c478bd9Sstevel@tonic-gate 	char *retstr;
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	if (zonestr == NULL) {
320*7c478bd9Sstevel@tonic-gate 		return (0);
321*7c478bd9Sstevel@tonic-gate 	}
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	addr = &sa->sin6_addr;
324*7c478bd9Sstevel@tonic-gate 	/*
325*7c478bd9Sstevel@tonic-gate 	 * Since this implementation only supports link scope addresses,
326*7c478bd9Sstevel@tonic-gate 	 * there is a one-to-one mapping between interface index and
327*7c478bd9Sstevel@tonic-gate 	 * sin6_scope_id.
328*7c478bd9Sstevel@tonic-gate 	 */
329*7c478bd9Sstevel@tonic-gate 	ifindex = sa->sin6_scope_id;
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	if ((retstr = if_indextoname(ifindex, zonestr)) != NULL) {
332*7c478bd9Sstevel@tonic-gate 		return (strlen(retstr));
333*7c478bd9Sstevel@tonic-gate 	} else {
334*7c478bd9Sstevel@tonic-gate 		int n;
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 		/*
337*7c478bd9Sstevel@tonic-gate 		 * Failed to convert ifindex into an interface name,
338*7c478bd9Sstevel@tonic-gate 		 * simply return the literal value of ifindex as
339*7c478bd9Sstevel@tonic-gate 		 * a string.
340*7c478bd9Sstevel@tonic-gate 		 */
341*7c478bd9Sstevel@tonic-gate 		if ((n = snprintf(zonestr, zonelen, "%u",
342*7c478bd9Sstevel@tonic-gate 		    ifindex)) < 0) {
343*7c478bd9Sstevel@tonic-gate 			return (0);
344*7c478bd9Sstevel@tonic-gate 		} else {
345*7c478bd9Sstevel@tonic-gate 			if (n >= zonelen) {
346*7c478bd9Sstevel@tonic-gate 				return (0);
347*7c478bd9Sstevel@tonic-gate 			}
348*7c478bd9Sstevel@tonic-gate 			return (n);
349*7c478bd9Sstevel@tonic-gate 		}
350*7c478bd9Sstevel@tonic-gate 	}
351*7c478bd9Sstevel@tonic-gate }
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate /*
355*7c478bd9Sstevel@tonic-gate  * This is a wrapper function for inet_ntop(). In case the af is AF_INET6
356*7c478bd9Sstevel@tonic-gate  * and the address pointed by src is a IPv4-mapped IPv6 address, it
357*7c478bd9Sstevel@tonic-gate  * returns printable IPv4 address, not IPv4-mapped IPv6 address. In other cases
358*7c478bd9Sstevel@tonic-gate  * it behaves just like inet_ntop().
359*7c478bd9Sstevel@tonic-gate  */
360*7c478bd9Sstevel@tonic-gate static const char *
_inet_ntop_native(int af,const void * src,char * dst,size_t size)361*7c478bd9Sstevel@tonic-gate _inet_ntop_native(int af, const void *src, char *dst, size_t size)
362*7c478bd9Sstevel@tonic-gate {
363*7c478bd9Sstevel@tonic-gate 	struct in_addr src4;
364*7c478bd9Sstevel@tonic-gate 	const char *result;
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	if (af == AF_INET6) {
367*7c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)) {
368*7c478bd9Sstevel@tonic-gate 			IN6_V4MAPPED_TO_INADDR((struct in6_addr *)src, &src4);
369*7c478bd9Sstevel@tonic-gate 			result = inet_ntop(AF_INET, &src4, dst, size);
370*7c478bd9Sstevel@tonic-gate 		} else {
371*7c478bd9Sstevel@tonic-gate 			result = inet_ntop(AF_INET6, src, dst, size);
372*7c478bd9Sstevel@tonic-gate 		}
373*7c478bd9Sstevel@tonic-gate 	} else {
374*7c478bd9Sstevel@tonic-gate 		result = inet_ntop(af, src, dst, size);
375*7c478bd9Sstevel@tonic-gate 	}
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 	return (result);
378*7c478bd9Sstevel@tonic-gate }
379