xref: /titanic_50/usr/src/lib/libnsl/nss/getipnodeby.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  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  * This file defines and implements the re-entrant getipnodebyname(),
27*7c478bd9Sstevel@tonic-gate  * getipnodebyaddr(), and freehostent() routines for IPv6. These routines
28*7c478bd9Sstevel@tonic-gate  * follow use the netdir_getbyYY() (see netdir_inet.c).
29*7c478bd9Sstevel@tonic-gate  *
30*7c478bd9Sstevel@tonic-gate  * lib/libnsl/nss/getipnodeby.c
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #include "mt.h"
36*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
37*7c478bd9Sstevel@tonic-gate #include <unistd.h>
38*7c478bd9Sstevel@tonic-gate #include <stropts.h>
39*7c478bd9Sstevel@tonic-gate #include <ctype.h>
40*7c478bd9Sstevel@tonic-gate #include <string.h>
41*7c478bd9Sstevel@tonic-gate #include <strings.h>
42*7c478bd9Sstevel@tonic-gate #include <netdb.h>
43*7c478bd9Sstevel@tonic-gate #include <stdio.h>
44*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
45*7c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
46*7c478bd9Sstevel@tonic-gate #include <rpc/trace.h>
47*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
50*7c478bd9Sstevel@tonic-gate #include <nss_netdir.h>
51*7c478bd9Sstevel@tonic-gate #include <net/if.h>
52*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
53*7c478bd9Sstevel@tonic-gate #include <netdir.h>
54*7c478bd9Sstevel@tonic-gate #include <thread.h>
55*7c478bd9Sstevel@tonic-gate #include <synch.h>
56*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
58*7c478bd9Sstevel@tonic-gate #include "nss.h"
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate #define	IPV6_LITERAL_CHAR	':'
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate /*
63*7c478bd9Sstevel@tonic-gate  * The number of nanoseconds getipnodebyname() waits before getting
64*7c478bd9Sstevel@tonic-gate  * fresh interface count information with SIOCGLIFNUM.  The default is
65*7c478bd9Sstevel@tonic-gate  * five minutes.
66*7c478bd9Sstevel@tonic-gate  */
67*7c478bd9Sstevel@tonic-gate #define	IFNUM_TIMEOUT	((hrtime_t)300 * NANOSEC)
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate /*
70*7c478bd9Sstevel@tonic-gate  * Bits in the bitfield returned by getipnodebyname_processflags().
71*7c478bd9Sstevel@tonic-gate  *
72*7c478bd9Sstevel@tonic-gate  * IPNODE_WANTIPV6	The user wants IPv6 addresses returned.
73*7c478bd9Sstevel@tonic-gate  * IPNODE_WANTIPV4	The user wants IPv4 addresses returned.
74*7c478bd9Sstevel@tonic-gate  * IPNODE_IPV4IFNOIPV6	The user only wants IPv4 addresses returned if no IPv6
75*7c478bd9Sstevel@tonic-gate  *			addresses are returned.
76*7c478bd9Sstevel@tonic-gate  * IPNODE_LOOKUPIPNODES	getipnodebyname() needs to lookup the name in ipnodes.
77*7c478bd9Sstevel@tonic-gate  * IPNODE_LOOKUPHOSTS	getipnodebyname() needs to lookup the name in hosts.
78*7c478bd9Sstevel@tonic-gate  * IPNODE_ISLITERAL	The name supplied is a literal address string.
79*7c478bd9Sstevel@tonic-gate  */
80*7c478bd9Sstevel@tonic-gate #define	IPNODE_WANTIPV6		0x00000001u
81*7c478bd9Sstevel@tonic-gate #define	IPNODE_WANTIPV4		0x00000002u
82*7c478bd9Sstevel@tonic-gate #define	IPNODE_IPV4IFNOIPV6	0x00000004u
83*7c478bd9Sstevel@tonic-gate #define	IPNODE_LOOKUPIPNODES	0x00000008u
84*7c478bd9Sstevel@tonic-gate #define	IPNODE_LOOKUPHOSTS	0x00000010u
85*7c478bd9Sstevel@tonic-gate #define	IPNODE_LITERAL		0x00000020u
86*7c478bd9Sstevel@tonic-gate #define	IPNODE_IPV4		(IPNODE_WANTIPV4 | IPNODE_IPV4IFNOIPV6)
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate /*
89*7c478bd9Sstevel@tonic-gate  * The default set of bits corresponding to a getipnodebyname() flags
90*7c478bd9Sstevel@tonic-gate  * argument of AI_DEFAULT.
91*7c478bd9Sstevel@tonic-gate  */
92*7c478bd9Sstevel@tonic-gate #define	IPNODE_DEFAULT (IPNODE_WANTIPV6 | IPNODE_IPV4 | \
93*7c478bd9Sstevel@tonic-gate 	IPNODE_LOOKUPIPNODES | IPNODE_LOOKUPHOSTS)
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate extern struct netconfig *__rpc_getconfip(char *);
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate static struct hostent *__mapv4tov6(struct hostent *, struct hostent *,
98*7c478bd9Sstevel@tonic-gate     nss_XbyY_buf_t *, int);
99*7c478bd9Sstevel@tonic-gate struct hostent *__mappedtov4(struct hostent *, int *);
100*7c478bd9Sstevel@tonic-gate static struct hostent *__filter_addresses(int, struct hostent *);
101*7c478bd9Sstevel@tonic-gate static int __find_mapped(struct hostent *, int);
102*7c478bd9Sstevel@tonic-gate static nss_XbyY_buf_t *__IPv6_alloc(int);
103*7c478bd9Sstevel@tonic-gate static void __IPv6_cleanup(nss_XbyY_buf_t *);
104*7c478bd9Sstevel@tonic-gate static int __ai_addrconfig(int);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate #ifdef PIC
108*7c478bd9Sstevel@tonic-gate struct hostent *
109*7c478bd9Sstevel@tonic-gate _uncached_getipnodebyname(const char *nam, struct hostent *result,
110*7c478bd9Sstevel@tonic-gate 	char *buffer, int buflen, int af_family, int flags, int *h_errnop)
111*7c478bd9Sstevel@tonic-gate {
112*7c478bd9Sstevel@tonic-gate 	return
113*7c478bd9Sstevel@tonic-gate 	(_switch_getipnodebyname_r(nam, result, buffer, buflen, af_family,
114*7c478bd9Sstevel@tonic-gate 					flags, h_errnop));
115*7c478bd9Sstevel@tonic-gate }
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate struct hostent *
118*7c478bd9Sstevel@tonic-gate _uncached_getipnodebyaddr(const char *addr, int length, int type,
119*7c478bd9Sstevel@tonic-gate 	struct hostent *result, char *buffer, int buflen, int *h_errnop)
120*7c478bd9Sstevel@tonic-gate {
121*7c478bd9Sstevel@tonic-gate 	if (type == AF_INET)
122*7c478bd9Sstevel@tonic-gate 		return (_switch_gethostbyaddr_r(addr, length, type,
123*7c478bd9Sstevel@tonic-gate 					result, buffer, buflen, h_errnop));
124*7c478bd9Sstevel@tonic-gate 	else if (type == AF_INET6)
125*7c478bd9Sstevel@tonic-gate 		return (_switch_getipnodebyaddr_r(addr, length, type,
126*7c478bd9Sstevel@tonic-gate 					result, buffer, buflen, h_errnop));
127*7c478bd9Sstevel@tonic-gate 	return (NULL);
128*7c478bd9Sstevel@tonic-gate }
129*7c478bd9Sstevel@tonic-gate #endif
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate /*
132*7c478bd9Sstevel@tonic-gate  * Given a name, an address family, and a set of flags, return a
133*7c478bd9Sstevel@tonic-gate  * bitfield that getipnodebyname() will use.
134*7c478bd9Sstevel@tonic-gate  */
135*7c478bd9Sstevel@tonic-gate static uint_t
136*7c478bd9Sstevel@tonic-gate getipnodebyname_processflags(const char *name, int af, int flags)
137*7c478bd9Sstevel@tonic-gate {
138*7c478bd9Sstevel@tonic-gate 	int		ifnum6, ifnum4;
139*7c478bd9Sstevel@tonic-gate 	uint_t		ipnode_bits = IPNODE_DEFAULT;
140*7c478bd9Sstevel@tonic-gate 	boolean_t	ipv6configured = B_FALSE;
141*7c478bd9Sstevel@tonic-gate 	boolean_t	ipv4configured = B_FALSE;
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	/*
144*7c478bd9Sstevel@tonic-gate 	 * If AI_ADDRCONFIG is specified, we need to determine the number
145*7c478bd9Sstevel@tonic-gate 	 * of addresses of each address family configured on the system as
146*7c478bd9Sstevel@tonic-gate 	 * appropriate.
147*7c478bd9Sstevel@tonic-gate 	 */
148*7c478bd9Sstevel@tonic-gate 	if (flags & AI_ADDRCONFIG) {
149*7c478bd9Sstevel@tonic-gate 		ipv6configured = (af == AF_INET6 &&
150*7c478bd9Sstevel@tonic-gate 		    __ai_addrconfig(AF_INET6) > 0);
151*7c478bd9Sstevel@tonic-gate 		ipv4configured = ((af == AF_INET || (flags & AI_V4MAPPED)) &&
152*7c478bd9Sstevel@tonic-gate 		    __ai_addrconfig(AF_INET) > 0);
153*7c478bd9Sstevel@tonic-gate 	}
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	/*
156*7c478bd9Sstevel@tonic-gate 	 * Determine what kinds of addresses the user is interested
157*7c478bd9Sstevel@tonic-gate 	 * in getting back.
158*7c478bd9Sstevel@tonic-gate 	 */
159*7c478bd9Sstevel@tonic-gate 	switch (af) {
160*7c478bd9Sstevel@tonic-gate 	case AF_INET6:
161*7c478bd9Sstevel@tonic-gate 		if ((flags & AI_ADDRCONFIG) && !ipv6configured)
162*7c478bd9Sstevel@tonic-gate 			ipnode_bits &= ~IPNODE_WANTIPV6;
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 		if (flags & AI_V4MAPPED) {
165*7c478bd9Sstevel@tonic-gate 			if ((flags & AI_ADDRCONFIG) && !ipv4configured) {
166*7c478bd9Sstevel@tonic-gate 				ipnode_bits &= ~IPNODE_IPV4;
167*7c478bd9Sstevel@tonic-gate 			} else if (flags & AI_ALL) {
168*7c478bd9Sstevel@tonic-gate 				ipnode_bits &= ~IPNODE_IPV4IFNOIPV6;
169*7c478bd9Sstevel@tonic-gate 			}
170*7c478bd9Sstevel@tonic-gate 		} else {
171*7c478bd9Sstevel@tonic-gate 			ipnode_bits &= ~IPNODE_IPV4;
172*7c478bd9Sstevel@tonic-gate 		}
173*7c478bd9Sstevel@tonic-gate 		break;
174*7c478bd9Sstevel@tonic-gate 	case AF_INET:
175*7c478bd9Sstevel@tonic-gate 		if ((flags & AI_ADDRCONFIG) && !ipv4configured)
176*7c478bd9Sstevel@tonic-gate 			ipnode_bits &= ~IPNODE_IPV4;
177*7c478bd9Sstevel@tonic-gate 		ipnode_bits &= ~IPNODE_WANTIPV6;
178*7c478bd9Sstevel@tonic-gate 		ipnode_bits &= ~IPNODE_IPV4IFNOIPV6;
179*7c478bd9Sstevel@tonic-gate 		break;
180*7c478bd9Sstevel@tonic-gate 	default:
181*7c478bd9Sstevel@tonic-gate 		ipnode_bits = 0;
182*7c478bd9Sstevel@tonic-gate 		break;
183*7c478bd9Sstevel@tonic-gate 	}
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	/*
186*7c478bd9Sstevel@tonic-gate 	 * If we're not looking for IPv4 addresses, don't bother looking
187*7c478bd9Sstevel@tonic-gate 	 * in hosts.
188*7c478bd9Sstevel@tonic-gate 	 */
189*7c478bd9Sstevel@tonic-gate 	if (!(ipnode_bits & IPNODE_WANTIPV4))
190*7c478bd9Sstevel@tonic-gate 		ipnode_bits &= ~IPNODE_LOOKUPHOSTS;
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	/*
193*7c478bd9Sstevel@tonic-gate 	 * Determine if name is a literal IP address.  This will
194*7c478bd9Sstevel@tonic-gate 	 * further narrow down what type of lookup we're going to do.
195*7c478bd9Sstevel@tonic-gate 	 */
196*7c478bd9Sstevel@tonic-gate 	if (strchr(name, IPV6_LITERAL_CHAR) != NULL) {
197*7c478bd9Sstevel@tonic-gate 		/* Literal IPv6 address */
198*7c478bd9Sstevel@tonic-gate 		ipnode_bits |= IPNODE_LITERAL;
199*7c478bd9Sstevel@tonic-gate 		/*
200*7c478bd9Sstevel@tonic-gate 		 * In s9 we accepted the literal without filtering independent
201*7c478bd9Sstevel@tonic-gate 		 * of what family was passed in hints.  We continue to do
202*7c478bd9Sstevel@tonic-gate 		 * this.
203*7c478bd9Sstevel@tonic-gate 		 */
204*7c478bd9Sstevel@tonic-gate 		ipnode_bits |= (IPNODE_WANTIPV6 | IPNODE_WANTIPV4);
205*7c478bd9Sstevel@tonic-gate 		ipnode_bits &= ~IPNODE_LOOKUPHOSTS;
206*7c478bd9Sstevel@tonic-gate 	} else if (inet_addr(name) != -1) {
207*7c478bd9Sstevel@tonic-gate 		/* Literal IPv4 address */
208*7c478bd9Sstevel@tonic-gate 		ipnode_bits |= (IPNODE_LITERAL | IPNODE_WANTIPV4);
209*7c478bd9Sstevel@tonic-gate 		ipnode_bits &= ~IPNODE_WANTIPV6;
210*7c478bd9Sstevel@tonic-gate 		ipnode_bits &= ~IPNODE_LOOKUPIPNODES;
211*7c478bd9Sstevel@tonic-gate 	}
212*7c478bd9Sstevel@tonic-gate 	return (ipnode_bits);
213*7c478bd9Sstevel@tonic-gate }
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate struct hostent *
216*7c478bd9Sstevel@tonic-gate getipnodebyname(const char *name, int af, int flags, int *error_num)
217*7c478bd9Sstevel@tonic-gate {
218*7c478bd9Sstevel@tonic-gate 	struct hostent		*hp = NULL;
219*7c478bd9Sstevel@tonic-gate 	nss_XbyY_buf_t		*buf4 = NULL;
220*7c478bd9Sstevel@tonic-gate 	nss_XbyY_buf_t		*buf6 = NULL;
221*7c478bd9Sstevel@tonic-gate 	struct netconfig	*nconf;
222*7c478bd9Sstevel@tonic-gate 	struct nss_netdirbyname_in	nssin;
223*7c478bd9Sstevel@tonic-gate 	union nss_netdirbyname_out	nssout;
224*7c478bd9Sstevel@tonic-gate 	int			ret;
225*7c478bd9Sstevel@tonic-gate 	uint_t			ipnode_bits;
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	trace1(TR_getipnodebyname, 0);
228*7c478bd9Sstevel@tonic-gate 	if ((nconf = __rpc_getconfip("udp")) == NULL &&
229*7c478bd9Sstevel@tonic-gate 	    (nconf = __rpc_getconfip("tcp")) == NULL) {
230*7c478bd9Sstevel@tonic-gate 		trace2(TR_getipnodebyname, 1, buflen);
231*7c478bd9Sstevel@tonic-gate 		*error_num = NO_RECOVERY;
232*7c478bd9Sstevel@tonic-gate 		return (NULL);
233*7c478bd9Sstevel@tonic-gate 	}
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	ipnode_bits = getipnodebyname_processflags(name, af, flags);
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	/* Make sure we have something to look up. */
238*7c478bd9Sstevel@tonic-gate 	if (!(ipnode_bits & (IPNODE_WANTIPV6 | IPNODE_WANTIPV4))) {
239*7c478bd9Sstevel@tonic-gate 		*error_num = HOST_NOT_FOUND;
240*7c478bd9Sstevel@tonic-gate 		goto cleanup;
241*7c478bd9Sstevel@tonic-gate 	}
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	/*
244*7c478bd9Sstevel@tonic-gate 	 * Perform the requested lookups.  We always look through
245*7c478bd9Sstevel@tonic-gate 	 * ipnodes first for both IPv4 and IPv6 addresses.  Depending
246*7c478bd9Sstevel@tonic-gate 	 * on what was returned and what was needed, we either filter
247*7c478bd9Sstevel@tonic-gate 	 * out the garbage, or ask for more using hosts.
248*7c478bd9Sstevel@tonic-gate 	 */
249*7c478bd9Sstevel@tonic-gate 	if (ipnode_bits & IPNODE_LOOKUPIPNODES) {
250*7c478bd9Sstevel@tonic-gate 		if ((buf6 = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == NULL) {
251*7c478bd9Sstevel@tonic-gate 			*error_num = NO_RECOVERY;
252*7c478bd9Sstevel@tonic-gate 			goto cleanup;
253*7c478bd9Sstevel@tonic-gate 		}
254*7c478bd9Sstevel@tonic-gate 		nssin.op_t = NSS_HOST6;
255*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host6.name = name;
256*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host6.buf = buf6->buffer;
257*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host6.buflen = buf6->buflen;
258*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host6.af_family = af;
259*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host6.flags = flags;
260*7c478bd9Sstevel@tonic-gate 		nssout.nss.host.hent = buf6->result;
261*7c478bd9Sstevel@tonic-gate 		nssout.nss.host.herrno_p = error_num;
262*7c478bd9Sstevel@tonic-gate 		ret = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout);
263*7c478bd9Sstevel@tonic-gate 		if (ret != ND_OK) {
264*7c478bd9Sstevel@tonic-gate 			__IPv6_cleanup(buf6);
265*7c478bd9Sstevel@tonic-gate 			buf6 = NULL;
266*7c478bd9Sstevel@tonic-gate 		} else if (ipnode_bits & IPNODE_WANTIPV4) {
267*7c478bd9Sstevel@tonic-gate 			/*
268*7c478bd9Sstevel@tonic-gate 			 * buf6 may have all that we need if we either
269*7c478bd9Sstevel@tonic-gate 			 * only wanted IPv4 addresses if there were no
270*7c478bd9Sstevel@tonic-gate 			 * IPv6 addresses returned, or if there are
271*7c478bd9Sstevel@tonic-gate 			 * IPv4-mapped addresses in buf6.  If either
272*7c478bd9Sstevel@tonic-gate 			 * of these are true, then there's no need to
273*7c478bd9Sstevel@tonic-gate 			 * look in hosts.
274*7c478bd9Sstevel@tonic-gate 			 */
275*7c478bd9Sstevel@tonic-gate 			if (ipnode_bits & IPNODE_IPV4IFNOIPV6 ||
276*7c478bd9Sstevel@tonic-gate 			    __find_mapped(buf6->result, 0) != 0) {
277*7c478bd9Sstevel@tonic-gate 				ipnode_bits &= ~IPNODE_LOOKUPHOSTS;
278*7c478bd9Sstevel@tonic-gate 			} else if (!(ipnode_bits & IPNODE_WANTIPV6)) {
279*7c478bd9Sstevel@tonic-gate 				/*
280*7c478bd9Sstevel@tonic-gate 				 * If all we're looking for are IPv4
281*7c478bd9Sstevel@tonic-gate 				 * addresses and there are none in
282*7c478bd9Sstevel@tonic-gate 				 * buf6 then buf6 is now useless.
283*7c478bd9Sstevel@tonic-gate 				 */
284*7c478bd9Sstevel@tonic-gate 				__IPv6_cleanup(buf6);
285*7c478bd9Sstevel@tonic-gate 				buf6 = NULL;
286*7c478bd9Sstevel@tonic-gate 			}
287*7c478bd9Sstevel@tonic-gate 		}
288*7c478bd9Sstevel@tonic-gate 	}
289*7c478bd9Sstevel@tonic-gate 	if (ipnode_bits & IPNODE_LOOKUPHOSTS) {
290*7c478bd9Sstevel@tonic-gate 		if ((buf4 = __IPv6_alloc(NSS_BUFLEN_HOSTS)) == NULL) {
291*7c478bd9Sstevel@tonic-gate 			*error_num = NO_RECOVERY;
292*7c478bd9Sstevel@tonic-gate 			goto cleanup;
293*7c478bd9Sstevel@tonic-gate 		}
294*7c478bd9Sstevel@tonic-gate 		nssin.op_t = NSS_HOST;
295*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.name = name;
296*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.buf = buf4->buffer;
297*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.buflen = buf4->buflen;
298*7c478bd9Sstevel@tonic-gate 		nssout.nss.host.hent = buf4->result;
299*7c478bd9Sstevel@tonic-gate 		nssout.nss.host.herrno_p = error_num;
300*7c478bd9Sstevel@tonic-gate 		ret = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout);
301*7c478bd9Sstevel@tonic-gate 		if (ret != ND_OK) {
302*7c478bd9Sstevel@tonic-gate 			__IPv6_cleanup(buf4);
303*7c478bd9Sstevel@tonic-gate 			buf4 = NULL;
304*7c478bd9Sstevel@tonic-gate 		}
305*7c478bd9Sstevel@tonic-gate 	}
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	if (buf6 == NULL && buf4 == NULL) {
308*7c478bd9Sstevel@tonic-gate 		*error_num = HOST_NOT_FOUND;
309*7c478bd9Sstevel@tonic-gate 		goto cleanup;
310*7c478bd9Sstevel@tonic-gate 	}
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	/* Extract the appropriate addresses from the returned buffer(s). */
313*7c478bd9Sstevel@tonic-gate 	switch (af) {
314*7c478bd9Sstevel@tonic-gate 	case AF_INET6: {
315*7c478bd9Sstevel@tonic-gate 		if (buf4 != NULL) {
316*7c478bd9Sstevel@tonic-gate 			nss_XbyY_buf_t *mergebuf;
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 			/*
319*7c478bd9Sstevel@tonic-gate 			 * The IPv4 results we have need to be
320*7c478bd9Sstevel@tonic-gate 			 * converted to IPv4-mapped addresses,
321*7c478bd9Sstevel@tonic-gate 			 * conditionally merged with the IPv6
322*7c478bd9Sstevel@tonic-gate 			 * results, and the end result needs to be
323*7c478bd9Sstevel@tonic-gate 			 * re-ordered.
324*7c478bd9Sstevel@tonic-gate 			 */
325*7c478bd9Sstevel@tonic-gate 			mergebuf = __IPv6_alloc(NSS_BUFLEN_IPNODES);
326*7c478bd9Sstevel@tonic-gate 			if (mergebuf == NULL) {
327*7c478bd9Sstevel@tonic-gate 				*error_num = NO_RECOVERY;
328*7c478bd9Sstevel@tonic-gate 				goto cleanup;
329*7c478bd9Sstevel@tonic-gate 			}
330*7c478bd9Sstevel@tonic-gate 			hp = __mapv4tov6(buf4->result,
331*7c478bd9Sstevel@tonic-gate 			    ((buf6 != NULL) ? buf6->result : NULL),
332*7c478bd9Sstevel@tonic-gate 			    mergebuf, 1);
333*7c478bd9Sstevel@tonic-gate 			if (hp != NULL)
334*7c478bd9Sstevel@tonic-gate 				order_haddrlist_af(AF_INET6, hp->h_addr_list);
335*7c478bd9Sstevel@tonic-gate 			else
336*7c478bd9Sstevel@tonic-gate 				*error_num = NO_RECOVERY;
337*7c478bd9Sstevel@tonic-gate 			free(mergebuf);
338*7c478bd9Sstevel@tonic-gate 		}
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 		if (buf4 == NULL && buf6 != NULL) {
341*7c478bd9Sstevel@tonic-gate 			hp = buf6->result;
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 			/*
344*7c478bd9Sstevel@tonic-gate 			 * We have what we need in buf6, but we may need
345*7c478bd9Sstevel@tonic-gate 			 * to filter out some addresses depending on what
346*7c478bd9Sstevel@tonic-gate 			 * is being asked for.
347*7c478bd9Sstevel@tonic-gate 			 */
348*7c478bd9Sstevel@tonic-gate 			if (!(ipnode_bits & IPNODE_WANTIPV4))
349*7c478bd9Sstevel@tonic-gate 				hp = __filter_addresses(AF_INET, buf6->result);
350*7c478bd9Sstevel@tonic-gate 			else if (!(ipnode_bits & IPNODE_WANTIPV6))
351*7c478bd9Sstevel@tonic-gate 				hp = __filter_addresses(AF_INET6, buf6->result);
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 			if (hp == NULL)
354*7c478bd9Sstevel@tonic-gate 				*error_num = NO_ADDRESS;
355*7c478bd9Sstevel@tonic-gate 		}
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 		break;
358*7c478bd9Sstevel@tonic-gate 	}
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	case AF_INET:
361*7c478bd9Sstevel@tonic-gate 		/* We could have results in buf6 or buf4, not both */
362*7c478bd9Sstevel@tonic-gate 		if (buf6 != NULL) {
363*7c478bd9Sstevel@tonic-gate 			/*
364*7c478bd9Sstevel@tonic-gate 			 * Extract the IPv4-mapped addresses from buf6
365*7c478bd9Sstevel@tonic-gate 			 * into hp.
366*7c478bd9Sstevel@tonic-gate 			 */
367*7c478bd9Sstevel@tonic-gate 			hp = __mappedtov4(buf6->result, error_num);
368*7c478bd9Sstevel@tonic-gate 		} else {
369*7c478bd9Sstevel@tonic-gate 			/* We have what we need in buf4. */
370*7c478bd9Sstevel@tonic-gate 			hp = buf4->result;
371*7c478bd9Sstevel@tonic-gate 			if (ipnode_bits & IPNODE_LITERAL) {
372*7c478bd9Sstevel@tonic-gate 				/*
373*7c478bd9Sstevel@tonic-gate 				 * There is a special case here for literal
374*7c478bd9Sstevel@tonic-gate 				 * IPv4 address strings.  The hosts
375*7c478bd9Sstevel@tonic-gate 				 * front-end sets h_aliases to a one
376*7c478bd9Sstevel@tonic-gate 				 * element array containing a single NULL
377*7c478bd9Sstevel@tonic-gate 				 * pointer (in ndaddr2hent()), while
378*7c478bd9Sstevel@tonic-gate 				 * getipnodebyname() requires h_aliases to
379*7c478bd9Sstevel@tonic-gate 				 * be a NULL pointer itself.  We're not
380*7c478bd9Sstevel@tonic-gate 				 * going to change the front-end since it
381*7c478bd9Sstevel@tonic-gate 				 * needs to remain backward compatible for
382*7c478bd9Sstevel@tonic-gate 				 * gethostbyname() and friends.  Just set
383*7c478bd9Sstevel@tonic-gate 				 * h_aliases to NULL here instead.
384*7c478bd9Sstevel@tonic-gate 				 */
385*7c478bd9Sstevel@tonic-gate 				hp->h_aliases = NULL;
386*7c478bd9Sstevel@tonic-gate 			}
387*7c478bd9Sstevel@tonic-gate 		}
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 		break;
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	default:
392*7c478bd9Sstevel@tonic-gate 		break;
393*7c478bd9Sstevel@tonic-gate 	}
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate cleanup:
396*7c478bd9Sstevel@tonic-gate 	/*
397*7c478bd9Sstevel@tonic-gate 	 * Free the memory we allocated, but make sure we don't free
398*7c478bd9Sstevel@tonic-gate 	 * the memory we're returning to the caller.
399*7c478bd9Sstevel@tonic-gate 	 */
400*7c478bd9Sstevel@tonic-gate 	if (buf6 != NULL) {
401*7c478bd9Sstevel@tonic-gate 		if (buf6->result == hp)
402*7c478bd9Sstevel@tonic-gate 			buf6->result = NULL;
403*7c478bd9Sstevel@tonic-gate 		__IPv6_cleanup(buf6);
404*7c478bd9Sstevel@tonic-gate 	}
405*7c478bd9Sstevel@tonic-gate 	if (buf4 != NULL) {
406*7c478bd9Sstevel@tonic-gate 		if (buf4->result == hp)
407*7c478bd9Sstevel@tonic-gate 			buf4->result = NULL;
408*7c478bd9Sstevel@tonic-gate 		__IPv6_cleanup(buf4);
409*7c478bd9Sstevel@tonic-gate 	}
410*7c478bd9Sstevel@tonic-gate 	(void) freenetconfigent(nconf);
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 	trace1(TR_getipnodebyname, 1);
413*7c478bd9Sstevel@tonic-gate 	return (hp);
414*7c478bd9Sstevel@tonic-gate }
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate /*
417*7c478bd9Sstevel@tonic-gate  * This is the IPv6 interface for "gethostbyaddr".
418*7c478bd9Sstevel@tonic-gate  */
419*7c478bd9Sstevel@tonic-gate struct hostent *
420*7c478bd9Sstevel@tonic-gate getipnodebyaddr(const void *src, size_t len, int type, int *error_num)
421*7c478bd9Sstevel@tonic-gate {
422*7c478bd9Sstevel@tonic-gate 	struct in6_addr *addr6 = 0;
423*7c478bd9Sstevel@tonic-gate 	struct in_addr *addr4 = 0;
424*7c478bd9Sstevel@tonic-gate 	nss_XbyY_buf_t *buf = 0;
425*7c478bd9Sstevel@tonic-gate 	nss_XbyY_buf_t *res = 0;
426*7c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
427*7c478bd9Sstevel@tonic-gate 	struct hostent *hp = 0;
428*7c478bd9Sstevel@tonic-gate 	struct	nss_netdirbyaddr_in nssin;
429*7c478bd9Sstevel@tonic-gate 	union	nss_netdirbyaddr_out nssout;
430*7c478bd9Sstevel@tonic-gate 	int neterr;
431*7c478bd9Sstevel@tonic-gate 	char tmpbuf[64];
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	trace2(TR_gethostbyaddr, 0, len);
434*7c478bd9Sstevel@tonic-gate 	if (type == AF_INET6) {
435*7c478bd9Sstevel@tonic-gate 		if ((addr6 = (struct in6_addr *)src) == NULL) {
436*7c478bd9Sstevel@tonic-gate 			*error_num = HOST_NOT_FOUND;
437*7c478bd9Sstevel@tonic-gate 			return (NULL);
438*7c478bd9Sstevel@tonic-gate 		}
439*7c478bd9Sstevel@tonic-gate 	} else if (type == AF_INET) {
440*7c478bd9Sstevel@tonic-gate 		if ((addr4 = (struct in_addr *)src) == NULL) {
441*7c478bd9Sstevel@tonic-gate 			*error_num = HOST_NOT_FOUND;
442*7c478bd9Sstevel@tonic-gate 			return (NULL);
443*7c478bd9Sstevel@tonic-gate 		}
444*7c478bd9Sstevel@tonic-gate 	} else {
445*7c478bd9Sstevel@tonic-gate 		*error_num = HOST_NOT_FOUND;
446*7c478bd9Sstevel@tonic-gate 		return (NULL);
447*7c478bd9Sstevel@tonic-gate 	}
448*7c478bd9Sstevel@tonic-gate 	/*
449*7c478bd9Sstevel@tonic-gate 	 * Specific case: query for "::"
450*7c478bd9Sstevel@tonic-gate 	 */
451*7c478bd9Sstevel@tonic-gate 	if (type == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(addr6)) {
452*7c478bd9Sstevel@tonic-gate 		*error_num = HOST_NOT_FOUND;
453*7c478bd9Sstevel@tonic-gate 		return (NULL);
454*7c478bd9Sstevel@tonic-gate 	}
455*7c478bd9Sstevel@tonic-gate 	/*
456*7c478bd9Sstevel@tonic-gate 	 * Step 1: IPv4-mapped address  or IPv4 Compat
457*7c478bd9Sstevel@tonic-gate 	 */
458*7c478bd9Sstevel@tonic-gate 	if ((type == AF_INET6 && len == 16) &&
459*7c478bd9Sstevel@tonic-gate 		((IN6_IS_ADDR_V4MAPPED(addr6)) ||
460*7c478bd9Sstevel@tonic-gate 		(IN6_IS_ADDR_V4COMPAT(addr6)))) {
461*7c478bd9Sstevel@tonic-gate 		if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
462*7c478bd9Sstevel@tonic-gate 			*error_num = NO_RECOVERY;
463*7c478bd9Sstevel@tonic-gate 			return (NULL);
464*7c478bd9Sstevel@tonic-gate 		}
465*7c478bd9Sstevel@tonic-gate 		if ((nconf = __rpc_getconfip("udp")) == NULL &&
466*7c478bd9Sstevel@tonic-gate 		    (nconf = __rpc_getconfip("tcp")) == NULL) {
467*7c478bd9Sstevel@tonic-gate 			trace3(TR__getipnodebyaddr, 0, len, buf->buflen);
468*7c478bd9Sstevel@tonic-gate 			*error_num = NO_RECOVERY;
469*7c478bd9Sstevel@tonic-gate 			__IPv6_cleanup(buf);
470*7c478bd9Sstevel@tonic-gate 			return (NULL);
471*7c478bd9Sstevel@tonic-gate 		}
472*7c478bd9Sstevel@tonic-gate 		nssin.op_t = NSS_HOST6;
473*7c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_V4COMPAT(addr6)) {
474*7c478bd9Sstevel@tonic-gate 			memcpy((void *)tmpbuf, (void *)addr6,
475*7c478bd9Sstevel@tonic-gate 						sizeof (*addr6));
476*7c478bd9Sstevel@tonic-gate 			tmpbuf[10] = 0xffU;
477*7c478bd9Sstevel@tonic-gate 			tmpbuf[11] = 0xffU;
478*7c478bd9Sstevel@tonic-gate 			nssin.arg.nss.host.addr = (const char *)tmpbuf;
479*7c478bd9Sstevel@tonic-gate 		} else {
480*7c478bd9Sstevel@tonic-gate 			nssin.arg.nss.host.addr = (const char *)addr6;
481*7c478bd9Sstevel@tonic-gate 		}
482*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.len = sizeof (struct in6_addr);
483*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.type = AF_INET6;
484*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.buf = buf->buffer;
485*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.buflen = buf->buflen;
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 		nssout.nss.host.hent = buf->result;
488*7c478bd9Sstevel@tonic-gate 		nssout.nss.host.herrno_p = error_num;
489*7c478bd9Sstevel@tonic-gate 		/*
490*7c478bd9Sstevel@tonic-gate 		 * We pass in nconf and let the implementation of the
491*7c478bd9Sstevel@tonic-gate 		 * long-named func decide whether to use the switch based on
492*7c478bd9Sstevel@tonic-gate 		 * nc_nlookups.
493*7c478bd9Sstevel@tonic-gate 		 */
494*7c478bd9Sstevel@tonic-gate 		neterr =
495*7c478bd9Sstevel@tonic-gate 			_get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 		(void) freenetconfigent(nconf);
498*7c478bd9Sstevel@tonic-gate 		if (neterr != ND_OK) {
499*7c478bd9Sstevel@tonic-gate 			/* Failover case, try hosts db for v4 address */
500*7c478bd9Sstevel@tonic-gate 			trace3(TR__getipnodebyaddr, 0, len, buf->buflen);
501*7c478bd9Sstevel@tonic-gate 			if (!gethostbyaddr_r(((char *)addr6) + 12,
502*7c478bd9Sstevel@tonic-gate 				sizeof (in_addr_t), AF_INET, buf->result,
503*7c478bd9Sstevel@tonic-gate 				buf->buffer, buf->buflen, error_num)) {
504*7c478bd9Sstevel@tonic-gate 				__IPv6_cleanup(buf);
505*7c478bd9Sstevel@tonic-gate 				return (NULL);
506*7c478bd9Sstevel@tonic-gate 			}
507*7c478bd9Sstevel@tonic-gate 			/* Found one, now format it into mapped/compat addr */
508*7c478bd9Sstevel@tonic-gate 			if ((res = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
509*7c478bd9Sstevel@tonic-gate 				__IPv6_cleanup(buf);
510*7c478bd9Sstevel@tonic-gate 				*error_num = NO_RECOVERY;
511*7c478bd9Sstevel@tonic-gate 				return (NULL);
512*7c478bd9Sstevel@tonic-gate 			}
513*7c478bd9Sstevel@tonic-gate 			/* Convert IPv4 to mapped/compat address w/name */
514*7c478bd9Sstevel@tonic-gate 			hp = res->result;
515*7c478bd9Sstevel@tonic-gate 			__mapv4tov6(buf->result, 0, res,
516*7c478bd9Sstevel@tonic-gate 						IN6_IS_ADDR_V4MAPPED(addr6));
517*7c478bd9Sstevel@tonic-gate 			__IPv6_cleanup(buf);
518*7c478bd9Sstevel@tonic-gate 			free(res);
519*7c478bd9Sstevel@tonic-gate 			return (hp);
520*7c478bd9Sstevel@tonic-gate 		}
521*7c478bd9Sstevel@tonic-gate 		/*
522*7c478bd9Sstevel@tonic-gate 		 * At this point, we'll have a v4mapped hostent. If that's
523*7c478bd9Sstevel@tonic-gate 		 * what was passed in, just return. If the request was a compat,
524*7c478bd9Sstevel@tonic-gate 		 * twiggle the two bytes to make the mapped address a compat.
525*7c478bd9Sstevel@tonic-gate 		 */
526*7c478bd9Sstevel@tonic-gate 		hp = buf->result;
527*7c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_V4COMPAT(addr6)) {
528*7c478bd9Sstevel@tonic-gate 			addr6 = (struct in6_addr *)hp->h_addr_list[0];
529*7c478bd9Sstevel@tonic-gate 			addr6->s6_addr[10] = 0;
530*7c478bd9Sstevel@tonic-gate 			addr6->s6_addr[11] = 0;
531*7c478bd9Sstevel@tonic-gate 		}
532*7c478bd9Sstevel@tonic-gate 		free(buf);
533*7c478bd9Sstevel@tonic-gate 		return (hp);
534*7c478bd9Sstevel@tonic-gate 	}
535*7c478bd9Sstevel@tonic-gate 	/*
536*7c478bd9Sstevel@tonic-gate 	 * Step 2: AF_INET, v4 lookup. Since we're going to search the
537*7c478bd9Sstevel@tonic-gate 	 * ipnodes (v6) path first, we need to treat this as a v4mapped
538*7c478bd9Sstevel@tonic-gate 	 * address. nscd(1m) caches v4 from ipnodes as mapped v6's. The
539*7c478bd9Sstevel@tonic-gate 	 * switch backend knows to lookup v4's (not v4mapped) from the
540*7c478bd9Sstevel@tonic-gate 	 * name services.
541*7c478bd9Sstevel@tonic-gate 	 */
542*7c478bd9Sstevel@tonic-gate 	if (type == AF_INET) {
543*7c478bd9Sstevel@tonic-gate 		struct in6_addr v4mapbuf;
544*7c478bd9Sstevel@tonic-gate 		addr6 = &v4mapbuf;
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 		IN6_INADDR_TO_V4MAPPED(addr4, addr6);
547*7c478bd9Sstevel@tonic-gate 		if ((nconf = __rpc_getconfip("udp")) == NULL &&
548*7c478bd9Sstevel@tonic-gate 		    (nconf = __rpc_getconfip("tcp")) == NULL) {
549*7c478bd9Sstevel@tonic-gate 			trace3(TR__getipnodebyaddr, 0, len, buf->buflen);
550*7c478bd9Sstevel@tonic-gate 			*error_num = NO_RECOVERY;
551*7c478bd9Sstevel@tonic-gate 			return (NULL);
552*7c478bd9Sstevel@tonic-gate 		}
553*7c478bd9Sstevel@tonic-gate 		if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
554*7c478bd9Sstevel@tonic-gate 			*error_num = NO_RECOVERY;
555*7c478bd9Sstevel@tonic-gate 			freenetconfigent(nconf);
556*7c478bd9Sstevel@tonic-gate 			return (NULL);
557*7c478bd9Sstevel@tonic-gate 		}
558*7c478bd9Sstevel@tonic-gate 		nssin.op_t = NSS_HOST6;
559*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.addr = (const char *)addr6;
560*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.len = sizeof (struct in6_addr);
561*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.type = AF_INET6;
562*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.buf = buf->buffer;
563*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.buflen = buf->buflen;
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 		nssout.nss.host.hent = buf->result;
566*7c478bd9Sstevel@tonic-gate 		nssout.nss.host.herrno_p = error_num;
567*7c478bd9Sstevel@tonic-gate 		/*
568*7c478bd9Sstevel@tonic-gate 		 * We pass in nconf and let the implementation of the
569*7c478bd9Sstevel@tonic-gate 		 * long-named func decide whether to use the switch based on
570*7c478bd9Sstevel@tonic-gate 		 * nc_nlookups.
571*7c478bd9Sstevel@tonic-gate 		 */
572*7c478bd9Sstevel@tonic-gate 		neterr =
573*7c478bd9Sstevel@tonic-gate 			_get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate 		(void) freenetconfigent(nconf);
576*7c478bd9Sstevel@tonic-gate 		if (neterr != ND_OK) {
577*7c478bd9Sstevel@tonic-gate 			/* Failover case, try hosts db for v4 address */
578*7c478bd9Sstevel@tonic-gate 			trace3(TR__getipnodebyaddr, 0, len, buf->buflen);
579*7c478bd9Sstevel@tonic-gate 			hp = buf->result;
580*7c478bd9Sstevel@tonic-gate 			if (!gethostbyaddr_r(src, len, type, buf->result,
581*7c478bd9Sstevel@tonic-gate 					buf->buffer, buf->buflen, error_num)) {
582*7c478bd9Sstevel@tonic-gate 				__IPv6_cleanup(buf);
583*7c478bd9Sstevel@tonic-gate 				return (NULL);
584*7c478bd9Sstevel@tonic-gate 			}
585*7c478bd9Sstevel@tonic-gate 			free(buf);
586*7c478bd9Sstevel@tonic-gate 			return (hp);
587*7c478bd9Sstevel@tonic-gate 		}
588*7c478bd9Sstevel@tonic-gate 		if ((hp = __mappedtov4(buf->result, error_num)) == NULL) {
589*7c478bd9Sstevel@tonic-gate 			__IPv6_cleanup(buf);
590*7c478bd9Sstevel@tonic-gate 			return (NULL);
591*7c478bd9Sstevel@tonic-gate 		}
592*7c478bd9Sstevel@tonic-gate 		__IPv6_cleanup(buf);
593*7c478bd9Sstevel@tonic-gate 		return (hp);
594*7c478bd9Sstevel@tonic-gate 	}
595*7c478bd9Sstevel@tonic-gate 	/*
596*7c478bd9Sstevel@tonic-gate 	 * Step 3: AF_INET6, plain vanilla v6 getipnodebyaddr() call.
597*7c478bd9Sstevel@tonic-gate 	 */
598*7c478bd9Sstevel@tonic-gate 	if (type == AF_INET6) {
599*7c478bd9Sstevel@tonic-gate 		if ((nconf = __rpc_getconfip("udp")) == NULL &&
600*7c478bd9Sstevel@tonic-gate 		    (nconf = __rpc_getconfip("tcp")) == NULL) {
601*7c478bd9Sstevel@tonic-gate 			trace3(TR__getipnodebyaddr, 0, len, buf->buflen);
602*7c478bd9Sstevel@tonic-gate 			*error_num = NO_RECOVERY;
603*7c478bd9Sstevel@tonic-gate 			return (NULL);
604*7c478bd9Sstevel@tonic-gate 		}
605*7c478bd9Sstevel@tonic-gate 		if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
606*7c478bd9Sstevel@tonic-gate 			*error_num = NO_RECOVERY;
607*7c478bd9Sstevel@tonic-gate 			freenetconfigent(nconf);
608*7c478bd9Sstevel@tonic-gate 			return (NULL);
609*7c478bd9Sstevel@tonic-gate 		}
610*7c478bd9Sstevel@tonic-gate 		nssin.op_t = NSS_HOST6;
611*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.addr = (const char *)addr6;
612*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.len = len;
613*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.type = type;
614*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.buf = buf->buffer;
615*7c478bd9Sstevel@tonic-gate 		nssin.arg.nss.host.buflen = buf->buflen;
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 		nssout.nss.host.hent = buf->result;
618*7c478bd9Sstevel@tonic-gate 		nssout.nss.host.herrno_p = error_num;
619*7c478bd9Sstevel@tonic-gate 		/*
620*7c478bd9Sstevel@tonic-gate 		 * We pass in nconf and let the implementation of the
621*7c478bd9Sstevel@tonic-gate 		 * long-named func decide whether to use the switch based on
622*7c478bd9Sstevel@tonic-gate 		 * nc_nlookups.
623*7c478bd9Sstevel@tonic-gate 		 */
624*7c478bd9Sstevel@tonic-gate 		neterr =
625*7c478bd9Sstevel@tonic-gate 			_get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate 		(void) freenetconfigent(nconf);
628*7c478bd9Sstevel@tonic-gate 		if (neterr != ND_OK) {
629*7c478bd9Sstevel@tonic-gate 			trace3(TR__getipnodebyaddr, 0, len, buf->buflen);
630*7c478bd9Sstevel@tonic-gate 			__IPv6_cleanup(buf);
631*7c478bd9Sstevel@tonic-gate 			return (NULL);
632*7c478bd9Sstevel@tonic-gate 		}
633*7c478bd9Sstevel@tonic-gate 		trace2(TR_gethostbyaddr, 1, len);
634*7c478bd9Sstevel@tonic-gate 		free(buf);
635*7c478bd9Sstevel@tonic-gate 		return (nssout.nss.host.hent);
636*7c478bd9Sstevel@tonic-gate 	}
637*7c478bd9Sstevel@tonic-gate 	/*
638*7c478bd9Sstevel@tonic-gate 	 * If we got here, unknown type.
639*7c478bd9Sstevel@tonic-gate 	 */
640*7c478bd9Sstevel@tonic-gate 	*error_num = HOST_NOT_FOUND;
641*7c478bd9Sstevel@tonic-gate 	return (NULL);
642*7c478bd9Sstevel@tonic-gate }
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate void
645*7c478bd9Sstevel@tonic-gate freehostent(struct hostent *hent)
646*7c478bd9Sstevel@tonic-gate {
647*7c478bd9Sstevel@tonic-gate 	free(hent);
648*7c478bd9Sstevel@tonic-gate }
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate static int
651*7c478bd9Sstevel@tonic-gate __ai_addrconfig(int af)
652*7c478bd9Sstevel@tonic-gate {
653*7c478bd9Sstevel@tonic-gate 	struct lifnum	lifn;
654*7c478bd9Sstevel@tonic-gate 	hrtime_t	now, *then;
655*7c478bd9Sstevel@tonic-gate 	static hrtime_t	then4, then6; /* the last time we updated ifnum# */
656*7c478bd9Sstevel@tonic-gate 	static int	ifnum4 = -1, ifnum6 = -1;
657*7c478bd9Sstevel@tonic-gate 	int		*num;
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 	switch (af) {
660*7c478bd9Sstevel@tonic-gate 	case AF_INET:
661*7c478bd9Sstevel@tonic-gate 		num = &ifnum4;
662*7c478bd9Sstevel@tonic-gate 		then = &then4;
663*7c478bd9Sstevel@tonic-gate 		break;
664*7c478bd9Sstevel@tonic-gate 	case AF_INET6:
665*7c478bd9Sstevel@tonic-gate 		num = &ifnum6;
666*7c478bd9Sstevel@tonic-gate 		then = &then6;
667*7c478bd9Sstevel@tonic-gate 		break;
668*7c478bd9Sstevel@tonic-gate 	default:
669*7c478bd9Sstevel@tonic-gate 		return (0);
670*7c478bd9Sstevel@tonic-gate 	}
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 	/*
673*7c478bd9Sstevel@tonic-gate 	 * We don't need to check this every time someone does a name
674*7c478bd9Sstevel@tonic-gate 	 * lookup.  Do it every IFNUM_TIMEOUT for each address family.
675*7c478bd9Sstevel@tonic-gate 	 *
676*7c478bd9Sstevel@tonic-gate 	 * There's no need to protect all of this with a lock.  The
677*7c478bd9Sstevel@tonic-gate 	 * worst that can happen is that we update the interface count
678*7c478bd9Sstevel@tonic-gate 	 * twice instead of once.  That's no big deal.
679*7c478bd9Sstevel@tonic-gate 	 */
680*7c478bd9Sstevel@tonic-gate 	now = gethrtime();
681*7c478bd9Sstevel@tonic-gate 	if (*num == -1 || ((now - *then) >= IFNUM_TIMEOUT)) {
682*7c478bd9Sstevel@tonic-gate 		lifn.lifn_family = af;
683*7c478bd9Sstevel@tonic-gate 		/*
684*7c478bd9Sstevel@tonic-gate 		 * We want to determine if this machine knows anything
685*7c478bd9Sstevel@tonic-gate 		 * at all about the address family; the status of the
686*7c478bd9Sstevel@tonic-gate 		 * interface is less important. Hence, set
687*7c478bd9Sstevel@tonic-gate 		 * 'lifn_flags' to zero.
688*7c478bd9Sstevel@tonic-gate 		 */
689*7c478bd9Sstevel@tonic-gate 		lifn.lifn_flags = 0;
690*7c478bd9Sstevel@tonic-gate 		if (nss_ioctl(af, SIOCGLIFNUM, &lifn) < 0)
691*7c478bd9Sstevel@tonic-gate 			return (-1);
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 		*num = lifn.lifn_count;
694*7c478bd9Sstevel@tonic-gate 		*then = now;
695*7c478bd9Sstevel@tonic-gate 	}
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	return (*num);
698*7c478bd9Sstevel@tonic-gate }
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate /*
701*7c478bd9Sstevel@tonic-gate  * This routine will either convert an IPv4 address to a mapped or compat
702*7c478bd9Sstevel@tonic-gate  * IPv6 (if he6 == NULL) or merge IPv6 (he6) addresses with mapped
703*7c478bd9Sstevel@tonic-gate  * v4 (he4) addresses. In either case, the results are returned in res.
704*7c478bd9Sstevel@tonic-gate  * Caller must provide all buffers.
705*7c478bd9Sstevel@tonic-gate  * Inputs:
706*7c478bd9Sstevel@tonic-gate  * 		he4	pointer to IPv4 buffer
707*7c478bd9Sstevel@tonic-gate  *		he6	pointer to IPv6 buffer (NULL if not merging v4/v6
708*7c478bd9Sstevel@tonic-gate  *		res	pointer to results buffer
709*7c478bd9Sstevel@tonic-gate  *		mapped	mapped == 1, map IPv4 : mapped == 0, compat IPv4
710*7c478bd9Sstevel@tonic-gate  *			mapped flag is ignored if he6 != NULL
711*7c478bd9Sstevel@tonic-gate  *
712*7c478bd9Sstevel@tonic-gate  * The results are packed into the res->buffer as follows:
713*7c478bd9Sstevel@tonic-gate  * <--------------- buffer + buflen -------------------------------------->
714*7c478bd9Sstevel@tonic-gate  * |-----------------|-----------------|----------------|----------------|
715*7c478bd9Sstevel@tonic-gate  * | pointers vector | pointers vector | aliases grow   | addresses grow |
716*7c478bd9Sstevel@tonic-gate  * | for addresses   | for aliases     |                |                |
717*7c478bd9Sstevel@tonic-gate  * | this way ->     | this way ->     | <- this way    |<- this way     |
718*7c478bd9Sstevel@tonic-gate  * |-----------------|-----------------|----------------|----------------|
719*7c478bd9Sstevel@tonic-gate  * | grows in PASS 1 | grows in PASS2  | grows in PASS2 | grows in PASS 1|
720*7c478bd9Sstevel@tonic-gate  */
721*7c478bd9Sstevel@tonic-gate static struct hostent *
722*7c478bd9Sstevel@tonic-gate __mapv4tov6(struct hostent *he4, struct hostent *he6, nss_XbyY_buf_t *res,
723*7c478bd9Sstevel@tonic-gate 		int mapped)
724*7c478bd9Sstevel@tonic-gate {
725*7c478bd9Sstevel@tonic-gate 	char	*buffer, *limit;
726*7c478bd9Sstevel@tonic-gate 	int	buflen = res->buflen;
727*7c478bd9Sstevel@tonic-gate 	struct	in6_addr *addr6p;
728*7c478bd9Sstevel@tonic-gate 	char	*buff_locp;
729*7c478bd9Sstevel@tonic-gate 	struct	hostent *host;
730*7c478bd9Sstevel@tonic-gate 	int	count = 0, len, i;
731*7c478bd9Sstevel@tonic-gate 	char	*h_namep;
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	if (he4 == NULL || res == NULL) {
734*7c478bd9Sstevel@tonic-gate 		return (NULL);
735*7c478bd9Sstevel@tonic-gate 	}
736*7c478bd9Sstevel@tonic-gate 	limit = res->buffer + buflen;
737*7c478bd9Sstevel@tonic-gate 	host = (struct hostent *)res->result;
738*7c478bd9Sstevel@tonic-gate 	buffer = res->buffer;
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	buff_locp = (char *)ROUND_DOWN(limit, sizeof (struct in6_addr));
741*7c478bd9Sstevel@tonic-gate 	host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **));
742*7c478bd9Sstevel@tonic-gate 	if ((char *)host->h_addr_list >= limit ||
743*7c478bd9Sstevel@tonic-gate 		buff_locp <= (char *)host->h_addr_list) {
744*7c478bd9Sstevel@tonic-gate 		return (NULL);
745*7c478bd9Sstevel@tonic-gate 	}
746*7c478bd9Sstevel@tonic-gate 	if (he6 == NULL) {
747*7c478bd9Sstevel@tonic-gate 		/*
748*7c478bd9Sstevel@tonic-gate 		 * If he6==NULL, map the v4 address into the v6 address format.
749*7c478bd9Sstevel@tonic-gate 		 * This is used for getipnodebyaddr() (single address, mapped or
750*7c478bd9Sstevel@tonic-gate 		 * compatible) or for v4 mapped for getipnodebyname(), which
751*7c478bd9Sstevel@tonic-gate 		 * could be multiple addresses. This could also be a literal
752*7c478bd9Sstevel@tonic-gate 		 * address string, which is why there is a inet_addr() call.
753*7c478bd9Sstevel@tonic-gate 		 */
754*7c478bd9Sstevel@tonic-gate 		for (i = 0; he4->h_addr_list[i] != NULL; i++) {
755*7c478bd9Sstevel@tonic-gate 			buff_locp -= sizeof (struct in6_addr);
756*7c478bd9Sstevel@tonic-gate 			if (buff_locp <=
757*7c478bd9Sstevel@tonic-gate 				(char *)&(host->h_addr_list[count + 1])) {
758*7c478bd9Sstevel@tonic-gate 			/*
759*7c478bd9Sstevel@tonic-gate 			 * Has to be room for the pointer to the address we're
760*7c478bd9Sstevel@tonic-gate 			 * about to add, as well as the final NULL ptr.
761*7c478bd9Sstevel@tonic-gate 			 */
762*7c478bd9Sstevel@tonic-gate 				return (NULL);
763*7c478bd9Sstevel@tonic-gate 			}
764*7c478bd9Sstevel@tonic-gate 			addr6p = (struct in6_addr *)buff_locp;
765*7c478bd9Sstevel@tonic-gate 			host->h_addr_list[count] = (char *)addr6p;
766*7c478bd9Sstevel@tonic-gate 			bzero(addr6p->s6_addr, sizeof (struct in6_addr));
767*7c478bd9Sstevel@tonic-gate 			if (mapped) {
768*7c478bd9Sstevel@tonic-gate 				addr6p->s6_addr[10] = 0xff;
769*7c478bd9Sstevel@tonic-gate 				addr6p->s6_addr[11] = 0xff;
770*7c478bd9Sstevel@tonic-gate 			}
771*7c478bd9Sstevel@tonic-gate 			bcopy((char *)he4->h_addr_list[i],
772*7c478bd9Sstevel@tonic-gate 				&addr6p->s6_addr[12], sizeof (struct in_addr));
773*7c478bd9Sstevel@tonic-gate 			++count;
774*7c478bd9Sstevel@tonic-gate 		}
775*7c478bd9Sstevel@tonic-gate 		/*
776*7c478bd9Sstevel@tonic-gate 		 * Set last array element to NULL and add cname as first alias
777*7c478bd9Sstevel@tonic-gate 		 */
778*7c478bd9Sstevel@tonic-gate 		host->h_addr_list[count] = NULL;
779*7c478bd9Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
780*7c478bd9Sstevel@tonic-gate 		count = 0;
781*7c478bd9Sstevel@tonic-gate 		if ((int)(inet_addr(he4->h_name)) != -1) {
782*7c478bd9Sstevel@tonic-gate 		/*
783*7c478bd9Sstevel@tonic-gate 		 * Literal address string, since we're mapping, we need the IPv6
784*7c478bd9Sstevel@tonic-gate 		 * V4 mapped literal address string for h_name.
785*7c478bd9Sstevel@tonic-gate 		 */
786*7c478bd9Sstevel@tonic-gate 			char	tmpstr[128];
787*7c478bd9Sstevel@tonic-gate 			inet_ntop(AF_INET6, host->h_addr_list[0], tmpstr,
788*7c478bd9Sstevel@tonic-gate 							sizeof (tmpstr));
789*7c478bd9Sstevel@tonic-gate 			buff_locp -= (len = strlen(tmpstr) + 1);
790*7c478bd9Sstevel@tonic-gate 			h_namep = tmpstr;
791*7c478bd9Sstevel@tonic-gate 			if (buff_locp <= (char *)(host->h_aliases))
792*7c478bd9Sstevel@tonic-gate 				return (NULL);
793*7c478bd9Sstevel@tonic-gate 			bcopy(h_namep, buff_locp, len);
794*7c478bd9Sstevel@tonic-gate 			host->h_name = buff_locp;
795*7c478bd9Sstevel@tonic-gate 			host->h_aliases = NULL; /* no aliases for literal */
796*7c478bd9Sstevel@tonic-gate 			host->h_length = sizeof (struct in6_addr);
797*7c478bd9Sstevel@tonic-gate 			host->h_addrtype = AF_INET6;
798*7c478bd9Sstevel@tonic-gate 			return (host); 		/* we're done, return result */
799*7c478bd9Sstevel@tonic-gate 		}
800*7c478bd9Sstevel@tonic-gate 		/*
801*7c478bd9Sstevel@tonic-gate 		 * Not a literal address string, so just copy h_name.
802*7c478bd9Sstevel@tonic-gate 		 */
803*7c478bd9Sstevel@tonic-gate 		buff_locp -= (len = strlen(he4->h_name) + 1);
804*7c478bd9Sstevel@tonic-gate 		h_namep = he4->h_name;
805*7c478bd9Sstevel@tonic-gate 		if (buff_locp <= (char *)(host->h_aliases))
806*7c478bd9Sstevel@tonic-gate 			return (NULL);
807*7c478bd9Sstevel@tonic-gate 		bcopy(h_namep, buff_locp, len);
808*7c478bd9Sstevel@tonic-gate 		host->h_name = buff_locp;
809*7c478bd9Sstevel@tonic-gate 		/*
810*7c478bd9Sstevel@tonic-gate 		 * Pass 2 (IPv4 aliases):
811*7c478bd9Sstevel@tonic-gate 		 */
812*7c478bd9Sstevel@tonic-gate 		for (i = 0; he4->h_aliases[i] != NULL; i++) {
813*7c478bd9Sstevel@tonic-gate 			buff_locp -= (len = strlen(he4->h_aliases[i]) + 1);
814*7c478bd9Sstevel@tonic-gate 			if (buff_locp <=
815*7c478bd9Sstevel@tonic-gate 					(char *)&(host->h_aliases[count + 1])) {
816*7c478bd9Sstevel@tonic-gate 			/*
817*7c478bd9Sstevel@tonic-gate 			 * Has to be room for the pointer to the address we're
818*7c478bd9Sstevel@tonic-gate 			 * about to add, as well as the final NULL ptr.
819*7c478bd9Sstevel@tonic-gate 			 */
820*7c478bd9Sstevel@tonic-gate 				return (NULL);
821*7c478bd9Sstevel@tonic-gate 			}
822*7c478bd9Sstevel@tonic-gate 			host->h_aliases[count] = buff_locp;
823*7c478bd9Sstevel@tonic-gate 			bcopy((char *)he4->h_aliases[i], buff_locp, len);
824*7c478bd9Sstevel@tonic-gate 			++count;
825*7c478bd9Sstevel@tonic-gate 		}
826*7c478bd9Sstevel@tonic-gate 		host->h_aliases[count] = NULL;
827*7c478bd9Sstevel@tonic-gate 		host->h_length = sizeof (struct in6_addr);
828*7c478bd9Sstevel@tonic-gate 		host->h_addrtype = AF_INET6;
829*7c478bd9Sstevel@tonic-gate 		return (host);
830*7c478bd9Sstevel@tonic-gate 	} else {
831*7c478bd9Sstevel@tonic-gate 		/*
832*7c478bd9Sstevel@tonic-gate 		 * Merge IPv4 mapped addresses with IPv6 addresses. The
833*7c478bd9Sstevel@tonic-gate 		 * IPv6 address will go in first, followed by the v4 mapped.
834*7c478bd9Sstevel@tonic-gate 		 *
835*7c478bd9Sstevel@tonic-gate 		 * Pass 1 (IPv6 addresses):
836*7c478bd9Sstevel@tonic-gate 		 */
837*7c478bd9Sstevel@tonic-gate 		for (i = 0; he6->h_addr_list[i] != NULL; i++) {
838*7c478bd9Sstevel@tonic-gate 			buff_locp -= sizeof (struct in6_addr);
839*7c478bd9Sstevel@tonic-gate 			if (buff_locp <=
840*7c478bd9Sstevel@tonic-gate 				(char *)&(host->h_addr_list[count + 1])) {
841*7c478bd9Sstevel@tonic-gate 			/*
842*7c478bd9Sstevel@tonic-gate 			 * Has to be room for the pointer to the address we're
843*7c478bd9Sstevel@tonic-gate 			 * about to add, as well as the final NULL ptr.
844*7c478bd9Sstevel@tonic-gate 			 */
845*7c478bd9Sstevel@tonic-gate 				return (NULL);
846*7c478bd9Sstevel@tonic-gate 			}
847*7c478bd9Sstevel@tonic-gate 			host->h_addr_list[count] = buff_locp;
848*7c478bd9Sstevel@tonic-gate 			bcopy((char *)he6->h_addr_list[i], buff_locp,
849*7c478bd9Sstevel@tonic-gate 						sizeof (struct in6_addr));
850*7c478bd9Sstevel@tonic-gate 			++count;
851*7c478bd9Sstevel@tonic-gate 		}
852*7c478bd9Sstevel@tonic-gate 		/*
853*7c478bd9Sstevel@tonic-gate 		 * Pass 1 (IPv4 mapped addresses):
854*7c478bd9Sstevel@tonic-gate 		 */
855*7c478bd9Sstevel@tonic-gate 		for (i = 0; he4->h_addr_list[i] != NULL; i++) {
856*7c478bd9Sstevel@tonic-gate 			buff_locp -= sizeof (struct in6_addr);
857*7c478bd9Sstevel@tonic-gate 			if (buff_locp <=
858*7c478bd9Sstevel@tonic-gate 				(char *)&(host->h_addr_list[count + 1])) {
859*7c478bd9Sstevel@tonic-gate 			/*
860*7c478bd9Sstevel@tonic-gate 			 * Has to be room for the pointer to the address we're
861*7c478bd9Sstevel@tonic-gate 			 * about to add, as well as the final NULL ptr.
862*7c478bd9Sstevel@tonic-gate 			 */
863*7c478bd9Sstevel@tonic-gate 				return (NULL);
864*7c478bd9Sstevel@tonic-gate 			}
865*7c478bd9Sstevel@tonic-gate 			addr6p = (struct in6_addr *)buff_locp;
866*7c478bd9Sstevel@tonic-gate 			host->h_addr_list[count] = (char *)addr6p;
867*7c478bd9Sstevel@tonic-gate 			bzero(addr6p->s6_addr, sizeof (struct in6_addr));
868*7c478bd9Sstevel@tonic-gate 			addr6p->s6_addr[10] = 0xff;
869*7c478bd9Sstevel@tonic-gate 			addr6p->s6_addr[11] = 0xff;
870*7c478bd9Sstevel@tonic-gate 			bcopy(he4->h_addr_list[i], &addr6p->s6_addr[12],
871*7c478bd9Sstevel@tonic-gate 						sizeof (struct in_addr));
872*7c478bd9Sstevel@tonic-gate 			++count;
873*7c478bd9Sstevel@tonic-gate 		}
874*7c478bd9Sstevel@tonic-gate 		/*
875*7c478bd9Sstevel@tonic-gate 		 * Pass 2 (IPv6 aliases, host name first). We start h_aliases
876*7c478bd9Sstevel@tonic-gate 		 * one after where h_addr_list array ended. This is where cname
877*7c478bd9Sstevel@tonic-gate 		 * is put, followed by all aliases. Reset count to 0, for index
878*7c478bd9Sstevel@tonic-gate 		 * in the h_aliases array.
879*7c478bd9Sstevel@tonic-gate 		 */
880*7c478bd9Sstevel@tonic-gate 		host->h_addr_list[count] = NULL;
881*7c478bd9Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
882*7c478bd9Sstevel@tonic-gate 		count = 0;
883*7c478bd9Sstevel@tonic-gate 		buff_locp -= (len = strlen(he6->h_name) + 1);
884*7c478bd9Sstevel@tonic-gate 		if (buff_locp <= (char *)(host->h_aliases))
885*7c478bd9Sstevel@tonic-gate 			return (NULL);
886*7c478bd9Sstevel@tonic-gate 		bcopy(he6->h_name, buff_locp, len);
887*7c478bd9Sstevel@tonic-gate 		host->h_name = buff_locp;
888*7c478bd9Sstevel@tonic-gate 		for (i = 0; he6->h_aliases[i] != NULL; i++) {
889*7c478bd9Sstevel@tonic-gate 			buff_locp -= (len = strlen(he6->h_aliases[i]) + 1);
890*7c478bd9Sstevel@tonic-gate 			if (buff_locp <=
891*7c478bd9Sstevel@tonic-gate 					(char *)&(host->h_aliases[count + 1])) {
892*7c478bd9Sstevel@tonic-gate 			/*
893*7c478bd9Sstevel@tonic-gate 			 * Has to be room for the pointer to the address we're
894*7c478bd9Sstevel@tonic-gate 			 * about to add, as well as the final NULL ptr.
895*7c478bd9Sstevel@tonic-gate 			 */
896*7c478bd9Sstevel@tonic-gate 				return (NULL);
897*7c478bd9Sstevel@tonic-gate 			}
898*7c478bd9Sstevel@tonic-gate 			host->h_aliases[count] = buff_locp;
899*7c478bd9Sstevel@tonic-gate 			bcopy((char *)he6->h_aliases[i], buff_locp, len);
900*7c478bd9Sstevel@tonic-gate 			++count;
901*7c478bd9Sstevel@tonic-gate 		}
902*7c478bd9Sstevel@tonic-gate 		/*
903*7c478bd9Sstevel@tonic-gate 		 * Pass 2 (IPv4 aliases):
904*7c478bd9Sstevel@tonic-gate 		 */
905*7c478bd9Sstevel@tonic-gate 		for (i = 0; he4->h_aliases[i] != NULL; i++) {
906*7c478bd9Sstevel@tonic-gate 			buff_locp -= (len = strlen(he4->h_aliases[i]) + 1);
907*7c478bd9Sstevel@tonic-gate 			if (buff_locp <=
908*7c478bd9Sstevel@tonic-gate 					(char *)&(host->h_aliases[count + 1])) {
909*7c478bd9Sstevel@tonic-gate 			/*
910*7c478bd9Sstevel@tonic-gate 			 * Has to be room for the pointer to the address we're
911*7c478bd9Sstevel@tonic-gate 			 * about to add, as well as the final NULL ptr.
912*7c478bd9Sstevel@tonic-gate 			 */
913*7c478bd9Sstevel@tonic-gate 				return (NULL);
914*7c478bd9Sstevel@tonic-gate 			}
915*7c478bd9Sstevel@tonic-gate 			host->h_aliases[count] = buff_locp;
916*7c478bd9Sstevel@tonic-gate 			bcopy((char *)he4->h_aliases[i], buff_locp, len);
917*7c478bd9Sstevel@tonic-gate 			++count;
918*7c478bd9Sstevel@tonic-gate 		}
919*7c478bd9Sstevel@tonic-gate 		host->h_aliases[count] = NULL;
920*7c478bd9Sstevel@tonic-gate 		host->h_length = sizeof (struct in6_addr);
921*7c478bd9Sstevel@tonic-gate 		host->h_addrtype = AF_INET6;
922*7c478bd9Sstevel@tonic-gate 		return (host);
923*7c478bd9Sstevel@tonic-gate 	}
924*7c478bd9Sstevel@tonic-gate }
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate /*
927*7c478bd9Sstevel@tonic-gate  * This routine will convert a mapped v4 hostent (AF_INET6) to a
928*7c478bd9Sstevel@tonic-gate  * AF_INET hostent. If no mapped addrs found, then a NULL is returned.
929*7c478bd9Sstevel@tonic-gate  * If mapped addrs found, then a new buffer is alloc'd and all the v4 mapped
930*7c478bd9Sstevel@tonic-gate  * addresses are extracted and copied to it. On sucess, a pointer to a new
931*7c478bd9Sstevel@tonic-gate  * hostent is returned.
932*7c478bd9Sstevel@tonic-gate  * There are two possible errors in which case a NULL is returned.
933*7c478bd9Sstevel@tonic-gate  * One of two error codes are returned:
934*7c478bd9Sstevel@tonic-gate  *
935*7c478bd9Sstevel@tonic-gate  * NO_RECOVERY - a malloc failed or the like for which there's no recovery.
936*7c478bd9Sstevel@tonic-gate  * NO_ADDRESS - after filtering all the v4, there was nothing left!
937*7c478bd9Sstevel@tonic-gate  *
938*7c478bd9Sstevel@tonic-gate  * Inputs:
939*7c478bd9Sstevel@tonic-gate  *              he              pointer to hostent with mapped v4 addresses
940*7c478bd9Sstevel@tonic-gate  *              filter_error    pointer to return error code
941*7c478bd9Sstevel@tonic-gate  * Return:
942*7c478bd9Sstevel@tonic-gate  *		pointer to a malloc'd hostent with v4 addresses.
943*7c478bd9Sstevel@tonic-gate  *
944*7c478bd9Sstevel@tonic-gate  * The results are packed into the res->buffer as follows:
945*7c478bd9Sstevel@tonic-gate  * <--------------- buffer + buflen -------------------------------------->
946*7c478bd9Sstevel@tonic-gate  * |-----------------|-----------------|----------------|----------------|
947*7c478bd9Sstevel@tonic-gate  * | pointers vector | pointers vector | aliases grow   | addresses grow |
948*7c478bd9Sstevel@tonic-gate  * | for addresses   | for aliases     |                |                |
949*7c478bd9Sstevel@tonic-gate  * | this way ->     | this way ->     | <- this way    |<- this way     |
950*7c478bd9Sstevel@tonic-gate  * |-----------------|-----------------|----------------|----------------|
951*7c478bd9Sstevel@tonic-gate  * | grows in PASS 1 | grows in PASS2  | grows in PASS2 | grows in PASS 1|
952*7c478bd9Sstevel@tonic-gate  */
953*7c478bd9Sstevel@tonic-gate struct hostent *
954*7c478bd9Sstevel@tonic-gate __mappedtov4(struct hostent *he, int *extract_error)
955*7c478bd9Sstevel@tonic-gate {
956*7c478bd9Sstevel@tonic-gate 	char	*buffer, *limit;
957*7c478bd9Sstevel@tonic-gate 	nss_XbyY_buf_t *res;
958*7c478bd9Sstevel@tonic-gate 	int	buflen = NSS_BUFLEN_HOSTS;
959*7c478bd9Sstevel@tonic-gate 	struct	in_addr *addr4p;
960*7c478bd9Sstevel@tonic-gate 	char	*buff_locp;
961*7c478bd9Sstevel@tonic-gate 	struct	hostent *host;
962*7c478bd9Sstevel@tonic-gate 	int	count = 0, len, i;
963*7c478bd9Sstevel@tonic-gate 	char	*h_namep;
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 	if (he == NULL) {
966*7c478bd9Sstevel@tonic-gate 		*extract_error = NO_ADDRESS;
967*7c478bd9Sstevel@tonic-gate 		return (NULL);
968*7c478bd9Sstevel@tonic-gate 	}
969*7c478bd9Sstevel@tonic-gate 	if ((__find_mapped(he, 0)) == 0) {
970*7c478bd9Sstevel@tonic-gate 		*extract_error = NO_ADDRESS;
971*7c478bd9Sstevel@tonic-gate 		return (NULL);
972*7c478bd9Sstevel@tonic-gate 	}
973*7c478bd9Sstevel@tonic-gate 	if ((res = __IPv6_alloc(NSS_BUFLEN_HOSTS)) == 0) {
974*7c478bd9Sstevel@tonic-gate 		*extract_error = NO_RECOVERY;
975*7c478bd9Sstevel@tonic-gate 		return (NULL);
976*7c478bd9Sstevel@tonic-gate 	}
977*7c478bd9Sstevel@tonic-gate 	limit = res->buffer + buflen;
978*7c478bd9Sstevel@tonic-gate 	host = (struct hostent *)res->result;
979*7c478bd9Sstevel@tonic-gate 	buffer = res->buffer;
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 	buff_locp = (char *)ROUND_DOWN(limit, sizeof (struct in_addr));
982*7c478bd9Sstevel@tonic-gate 	host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **));
983*7c478bd9Sstevel@tonic-gate 	if ((char *)host->h_addr_list >= limit ||
984*7c478bd9Sstevel@tonic-gate 		buff_locp <= (char *)host->h_addr_list)
985*7c478bd9Sstevel@tonic-gate 		goto cleanup;
986*7c478bd9Sstevel@tonic-gate 	/*
987*7c478bd9Sstevel@tonic-gate 	 * "Unmap" the v4 mapped address(es) into a v4 hostent format.
988*7c478bd9Sstevel@tonic-gate 	 * This is used for getipnodebyaddr() (single address) or for
989*7c478bd9Sstevel@tonic-gate 	 * v4 mapped for getipnodebyname(), which could be multiple
990*7c478bd9Sstevel@tonic-gate 	 * addresses. This could also be a literal address string,
991*7c478bd9Sstevel@tonic-gate 	 * which is why there is a inet_addr() call.
992*7c478bd9Sstevel@tonic-gate 	 */
993*7c478bd9Sstevel@tonic-gate 		for (i = 0; he->h_addr_list[i] != NULL; i++) {
994*7c478bd9Sstevel@tonic-gate 			if (!IN6_IS_ADDR_V4MAPPED((struct in6_addr *)
995*7c478bd9Sstevel@tonic-gate 							he->h_addr_list[i]))
996*7c478bd9Sstevel@tonic-gate 			continue;
997*7c478bd9Sstevel@tonic-gate 			buff_locp -= sizeof (struct in6_addr);
998*7c478bd9Sstevel@tonic-gate 			/*
999*7c478bd9Sstevel@tonic-gate 			 * Has to be room for the pointer to the address we're
1000*7c478bd9Sstevel@tonic-gate 			 * about to add, as well as the final NULL ptr.
1001*7c478bd9Sstevel@tonic-gate 			 */
1002*7c478bd9Sstevel@tonic-gate 			if (buff_locp <=
1003*7c478bd9Sstevel@tonic-gate 				(char *)&(host->h_addr_list[count + 1]))
1004*7c478bd9Sstevel@tonic-gate 				goto cleanup;
1005*7c478bd9Sstevel@tonic-gate 			addr4p = (struct in_addr *)buff_locp;
1006*7c478bd9Sstevel@tonic-gate 			host->h_addr_list[count] = (char *)addr4p;
1007*7c478bd9Sstevel@tonic-gate 			bzero((char *)&addr4p->s_addr,
1008*7c478bd9Sstevel@tonic-gate 						sizeof (struct in_addr));
1009*7c478bd9Sstevel@tonic-gate 			IN6_V4MAPPED_TO_INADDR(
1010*7c478bd9Sstevel@tonic-gate 					(struct in6_addr *)he->h_addr_list[i],
1011*7c478bd9Sstevel@tonic-gate 					addr4p);
1012*7c478bd9Sstevel@tonic-gate 			++count;
1013*7c478bd9Sstevel@tonic-gate 		}
1014*7c478bd9Sstevel@tonic-gate 		/*
1015*7c478bd9Sstevel@tonic-gate 		 * Set last array element to NULL and add cname as first alias
1016*7c478bd9Sstevel@tonic-gate 		 */
1017*7c478bd9Sstevel@tonic-gate 		host->h_addr_list[count] = NULL;
1018*7c478bd9Sstevel@tonic-gate 		host->h_aliases = host->h_addr_list + count + 1;
1019*7c478bd9Sstevel@tonic-gate 		count = 0;
1020*7c478bd9Sstevel@tonic-gate 		/* Copy official host name */
1021*7c478bd9Sstevel@tonic-gate 		buff_locp -= (len = strlen(he->h_name) + 1);
1022*7c478bd9Sstevel@tonic-gate 		h_namep = he->h_name;
1023*7c478bd9Sstevel@tonic-gate 		if (buff_locp <= (char *)(host->h_aliases))
1024*7c478bd9Sstevel@tonic-gate 			goto cleanup;
1025*7c478bd9Sstevel@tonic-gate 		bcopy(h_namep, buff_locp, len);
1026*7c478bd9Sstevel@tonic-gate 		host->h_name = buff_locp;
1027*7c478bd9Sstevel@tonic-gate 		/*
1028*7c478bd9Sstevel@tonic-gate 		 * Pass 2 (IPv4 aliases):
1029*7c478bd9Sstevel@tonic-gate 		 */
1030*7c478bd9Sstevel@tonic-gate 		for (i = 0; he->h_aliases[i] != NULL; i++) {
1031*7c478bd9Sstevel@tonic-gate 			buff_locp -= (len = strlen(he->h_aliases[i]) + 1);
1032*7c478bd9Sstevel@tonic-gate 			/*
1033*7c478bd9Sstevel@tonic-gate 			 * Has to be room for the pointer to the address we're
1034*7c478bd9Sstevel@tonic-gate 			 * about to add, as well as the final NULL ptr.
1035*7c478bd9Sstevel@tonic-gate 			 */
1036*7c478bd9Sstevel@tonic-gate 			if (buff_locp <=
1037*7c478bd9Sstevel@tonic-gate 					(char *)&(host->h_aliases[count + 1]))
1038*7c478bd9Sstevel@tonic-gate 				goto cleanup;
1039*7c478bd9Sstevel@tonic-gate 			host->h_aliases[count] = buff_locp;
1040*7c478bd9Sstevel@tonic-gate 			bcopy((char *)he->h_aliases[i], buff_locp, len);
1041*7c478bd9Sstevel@tonic-gate 			++count;
1042*7c478bd9Sstevel@tonic-gate 		}
1043*7c478bd9Sstevel@tonic-gate 		host->h_aliases[count] = NULL;
1044*7c478bd9Sstevel@tonic-gate 		host->h_length = sizeof (struct in_addr);
1045*7c478bd9Sstevel@tonic-gate 		host->h_addrtype = AF_INET;
1046*7c478bd9Sstevel@tonic-gate 		free(res);
1047*7c478bd9Sstevel@tonic-gate 		return (host);
1048*7c478bd9Sstevel@tonic-gate cleanup:
1049*7c478bd9Sstevel@tonic-gate 	*extract_error = NO_RECOVERY;
1050*7c478bd9Sstevel@tonic-gate 	(void) __IPv6_cleanup(res);
1051*7c478bd9Sstevel@tonic-gate 	return (NULL);
1052*7c478bd9Sstevel@tonic-gate }
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate /*
1055*7c478bd9Sstevel@tonic-gate  * This routine takes as input a pointer to a hostent and filters out
1056*7c478bd9Sstevel@tonic-gate  * the type of addresses specified by the af argument.  AF_INET
1057*7c478bd9Sstevel@tonic-gate  * indicates that the caller wishes to filter out IPv4-mapped
1058*7c478bd9Sstevel@tonic-gate  * addresses, and AF_INET6 indicates that the caller wishes to filter
1059*7c478bd9Sstevel@tonic-gate  * out IPv6 addresses which aren't IPv4-mapped.  If filtering would
1060*7c478bd9Sstevel@tonic-gate  * result in all addresses being filtered out, a NULL pointer is returned.
1061*7c478bd9Sstevel@tonic-gate  * Otherwise, the he pointer passed in is returned, even if no addresses
1062*7c478bd9Sstevel@tonic-gate  * were filtered out.
1063*7c478bd9Sstevel@tonic-gate  */
1064*7c478bd9Sstevel@tonic-gate static struct hostent *
1065*7c478bd9Sstevel@tonic-gate __filter_addresses(int af, struct hostent *he)
1066*7c478bd9Sstevel@tonic-gate {
1067*7c478bd9Sstevel@tonic-gate 	struct in6_addr	**in6addrlist, **in6addr;
1068*7c478bd9Sstevel@tonic-gate 	boolean_t	isipv4mapped;
1069*7c478bd9Sstevel@tonic-gate 	int		i = 0;
1070*7c478bd9Sstevel@tonic-gate 	char		addrstr[INET6_ADDRSTRLEN];
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate 	if (he == NULL)
1073*7c478bd9Sstevel@tonic-gate 		return (NULL);
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate 	in6addrlist = (struct in6_addr **)he->h_addr_list;
1076*7c478bd9Sstevel@tonic-gate 	for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) {
1077*7c478bd9Sstevel@tonic-gate 		isipv4mapped = IN6_IS_ADDR_V4MAPPED(*in6addr);
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 		if ((af == AF_INET && !isipv4mapped) ||
1080*7c478bd9Sstevel@tonic-gate 		    (af == AF_INET6 && isipv4mapped)) {
1081*7c478bd9Sstevel@tonic-gate 			if (in6addrlist[i] != *in6addr)
1082*7c478bd9Sstevel@tonic-gate 				in6addrlist[i] = *in6addr;
1083*7c478bd9Sstevel@tonic-gate 			i++;
1084*7c478bd9Sstevel@tonic-gate 		}
1085*7c478bd9Sstevel@tonic-gate 	}
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate 	if (i == 0) {
1088*7c478bd9Sstevel@tonic-gate 		/* We filtered everything out. */
1089*7c478bd9Sstevel@tonic-gate 		return (NULL);
1090*7c478bd9Sstevel@tonic-gate 	} else {
1091*7c478bd9Sstevel@tonic-gate 		/* NULL terminate the list and return the hostent */
1092*7c478bd9Sstevel@tonic-gate 		in6addrlist[i] = NULL;
1093*7c478bd9Sstevel@tonic-gate 		return (he);
1094*7c478bd9Sstevel@tonic-gate 	}
1095*7c478bd9Sstevel@tonic-gate }
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate /*
1098*7c478bd9Sstevel@tonic-gate  * This routine searches a hostent for v4 mapped IPv6 addresses.
1099*7c478bd9Sstevel@tonic-gate  * he		hostent structure to seach
1100*7c478bd9Sstevel@tonic-gate  * find_both	flag indicating if only want mapped or both map'd and v6
1101*7c478bd9Sstevel@tonic-gate  * return values:
1102*7c478bd9Sstevel@tonic-gate  * 			0 = No mapped addresses
1103*7c478bd9Sstevel@tonic-gate  *			1 = Mapped v4 address found (returns on first one found)
1104*7c478bd9Sstevel@tonic-gate  *			2 = Both v6 and v4 mapped are present
1105*7c478bd9Sstevel@tonic-gate  *
1106*7c478bd9Sstevel@tonic-gate  * If hostent passed in with no addresses, zero will be returned.
1107*7c478bd9Sstevel@tonic-gate  */
1108*7c478bd9Sstevel@tonic-gate 
1109*7c478bd9Sstevel@tonic-gate static int
1110*7c478bd9Sstevel@tonic-gate __find_mapped(struct hostent *he, int find_both)
1111*7c478bd9Sstevel@tonic-gate {
1112*7c478bd9Sstevel@tonic-gate 	int i;
1113*7c478bd9Sstevel@tonic-gate 	int mapd_found = 0;
1114*7c478bd9Sstevel@tonic-gate 	int v6_found = 0;
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate 	for (i = 0; he->h_addr_list[i] != NULL; i++) {
1117*7c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_V4MAPPED(
1118*7c478bd9Sstevel@tonic-gate 				(struct in6_addr *)he->h_addr_list[i])) {
1119*7c478bd9Sstevel@tonic-gate 			if (find_both)
1120*7c478bd9Sstevel@tonic-gate 				mapd_found = 1;
1121*7c478bd9Sstevel@tonic-gate 			else
1122*7c478bd9Sstevel@tonic-gate 				return (1);
1123*7c478bd9Sstevel@tonic-gate 		} else {
1124*7c478bd9Sstevel@tonic-gate 			v6_found = 1;
1125*7c478bd9Sstevel@tonic-gate 		}
1126*7c478bd9Sstevel@tonic-gate 		/* save some iterations once both found */
1127*7c478bd9Sstevel@tonic-gate 		if (mapd_found && v6_found)
1128*7c478bd9Sstevel@tonic-gate 			return (2);
1129*7c478bd9Sstevel@tonic-gate 	}
1130*7c478bd9Sstevel@tonic-gate 	return (mapd_found);
1131*7c478bd9Sstevel@tonic-gate }
1132*7c478bd9Sstevel@tonic-gate 
1133*7c478bd9Sstevel@tonic-gate /*
1134*7c478bd9Sstevel@tonic-gate  * This routine was added specifically for the IPv6 getipnodeby*() APIs. This
1135*7c478bd9Sstevel@tonic-gate  * separates the result pointer (ptr to hostent+data buf) from the
1136*7c478bd9Sstevel@tonic-gate  * nss_XbyY_buf_t ptr (required for nsswitch API). The returned hostent ptr
1137*7c478bd9Sstevel@tonic-gate  * can be passed to freehostent() and freed independently.
1138*7c478bd9Sstevel@tonic-gate  *
1139*7c478bd9Sstevel@tonic-gate  *   bufp->result    bufp->buffer
1140*7c478bd9Sstevel@tonic-gate  *		|		|
1141*7c478bd9Sstevel@tonic-gate  *		V		V
1142*7c478bd9Sstevel@tonic-gate  *		------------------------------------------------...--
1143*7c478bd9Sstevel@tonic-gate  *		|struct hostent	|addresses		     aliases |
1144*7c478bd9Sstevel@tonic-gate  *		------------------------------------------------...--
1145*7c478bd9Sstevel@tonic-gate  *		|               |<--------bufp->buflen-------------->|
1146*7c478bd9Sstevel@tonic-gate  */
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate #define	ALIGN(x) ((((long)(x)) + sizeof (long) - 1) & ~(sizeof (long) - 1))
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate static nss_XbyY_buf_t *
1151*7c478bd9Sstevel@tonic-gate __IPv6_alloc(int bufsz)
1152*7c478bd9Sstevel@tonic-gate {
1153*7c478bd9Sstevel@tonic-gate 	nss_XbyY_buf_t *bufp;
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 	if ((bufp = malloc(sizeof (nss_XbyY_buf_t))) == NULL)
1156*7c478bd9Sstevel@tonic-gate 		return (NULL);
1157*7c478bd9Sstevel@tonic-gate 
1158*7c478bd9Sstevel@tonic-gate 	if ((bufp->result = malloc(ALIGN(sizeof (struct hostent)) + bufsz)) ==
1159*7c478bd9Sstevel@tonic-gate 	    NULL) {
1160*7c478bd9Sstevel@tonic-gate 		free(bufp);
1161*7c478bd9Sstevel@tonic-gate 		return (NULL);
1162*7c478bd9Sstevel@tonic-gate 	}
1163*7c478bd9Sstevel@tonic-gate 	bufp->buffer = (char *)(bufp->result) + sizeof (struct hostent);
1164*7c478bd9Sstevel@tonic-gate 	bufp->buflen = bufsz;
1165*7c478bd9Sstevel@tonic-gate 	return (bufp);
1166*7c478bd9Sstevel@tonic-gate }
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate /*
1169*7c478bd9Sstevel@tonic-gate  * This routine is use only for error return cleanup. This will free the
1170*7c478bd9Sstevel@tonic-gate  * hostent pointer, so don't use for successful returns.
1171*7c478bd9Sstevel@tonic-gate  */
1172*7c478bd9Sstevel@tonic-gate static void
1173*7c478bd9Sstevel@tonic-gate __IPv6_cleanup(nss_XbyY_buf_t *bufp)
1174*7c478bd9Sstevel@tonic-gate {
1175*7c478bd9Sstevel@tonic-gate 	if (bufp == NULL)
1176*7c478bd9Sstevel@tonic-gate 		return;
1177*7c478bd9Sstevel@tonic-gate 	if (bufp->result != NULL)
1178*7c478bd9Sstevel@tonic-gate 		free(bufp->result);
1179*7c478bd9Sstevel@tonic-gate 	free(bufp);
1180*7c478bd9Sstevel@tonic-gate }
1181