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