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 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  * lib/libnsl/nss/netdir_inet.c
27*7c478bd9Sstevel@tonic-gate  *
28*7c478bd9Sstevel@tonic-gate  * This is where we have chosen to combine every useful bit of code for
29*7c478bd9Sstevel@tonic-gate  * all the Solaris frontends to lookup hosts, services, and netdir information
30*7c478bd9Sstevel@tonic-gate  * for inet family (udp, tcp) transports. gethostbyYY(), getservbyYY(), and
31*7c478bd9Sstevel@tonic-gate  * netdir_getbyYY() are all implemented on top of this code. Similarly,
32*7c478bd9Sstevel@tonic-gate  * netdir_options, taddr2uaddr, and uaddr2taddr for inet transports also
33*7c478bd9Sstevel@tonic-gate  * find a home here.
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  * If the netconfig structure supplied has NO nametoaddr libs (i.e. a "-"
36*7c478bd9Sstevel@tonic-gate  * in /etc/netconfig), this code calls the name service switch, and
37*7c478bd9Sstevel@tonic-gate  * therefore, /etc/nsswitch.conf is effectively the only place that
38*7c478bd9Sstevel@tonic-gate  * dictates hosts/serv lookup policy.
39*7c478bd9Sstevel@tonic-gate  * If an administrator chooses to bypass the name service switch by
40*7c478bd9Sstevel@tonic-gate  * specifying third party supplied nametoaddr libs in /etc/netconfig, this
41*7c478bd9Sstevel@tonic-gate  * implementation does NOT call the name service switch, it merely loops
42*7c478bd9Sstevel@tonic-gate  * through the nametoaddr libs. In this case, if this code was called
43*7c478bd9Sstevel@tonic-gate  * from gethost/servbyYY() we marshal the inet specific struct into
44*7c478bd9Sstevel@tonic-gate  * transport independent netbuf or hostserv, and unmarshal the resulting
45*7c478bd9Sstevel@tonic-gate  * nd_addrlist or hostservlist back into hostent and servent, as the case
46*7c478bd9Sstevel@tonic-gate  * may be.
47*7c478bd9Sstevel@tonic-gate  *
48*7c478bd9Sstevel@tonic-gate  * Goes without saying that most of the future bugs in gethost/servbyYY
49*7c478bd9Sstevel@tonic-gate  * and netdir_getbyYY are lurking somewhere here.
50*7c478bd9Sstevel@tonic-gate  */
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate #include "mt.h"
55*7c478bd9Sstevel@tonic-gate #include <ctype.h>
56*7c478bd9Sstevel@tonic-gate #include <stdio.h>
57*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
58*7c478bd9Sstevel@tonic-gate #include <string.h>
59*7c478bd9Sstevel@tonic-gate #include <unistd.h>
60*7c478bd9Sstevel@tonic-gate #include <stropts.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
66*7c478bd9Sstevel@tonic-gate #include <errno.h>
67*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
68*7c478bd9Sstevel@tonic-gate #include <thread.h>
69*7c478bd9Sstevel@tonic-gate #include <synch.h>
70*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
71*7c478bd9Sstevel@tonic-gate #include <netdb.h>
72*7c478bd9Sstevel@tonic-gate #include <netconfig.h>
73*7c478bd9Sstevel@tonic-gate #include <netdir.h>
74*7c478bd9Sstevel@tonic-gate #include <tiuser.h>
75*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
76*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
77*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
78*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
79*7c478bd9Sstevel@tonic-gate #include <net/if.h>
80*7c478bd9Sstevel@tonic-gate #include <inet/ip.h>
81*7c478bd9Sstevel@tonic-gate #include <inet/ip6_asp.h>
82*7c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
83*7c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
84*7c478bd9Sstevel@tonic-gate #include <nss_netdir.h>
85*7c478bd9Sstevel@tonic-gate #include <rpc/trace.h>
86*7c478bd9Sstevel@tonic-gate #include <syslog.h>
87*7c478bd9Sstevel@tonic-gate #include <nsswitch.h>
88*7c478bd9Sstevel@tonic-gate #include "nss.h"
89*7c478bd9Sstevel@tonic-gate #include "nsl_stdio_prv.h"
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate #define	MAXIFS 32
92*7c478bd9Sstevel@tonic-gate #define	UDPDEV	"/dev/udp"
93*7c478bd9Sstevel@tonic-gate #define	UDP6DEV	"/dev/udp6"
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate #define	GETHOSTBUF(host_buf)					\
96*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_ALLOC(&host_buf, sizeof (struct hostent), NSS_BUFLEN_HOSTS)
97*7c478bd9Sstevel@tonic-gate #define	GETSERVBUF(serv_buf)					\
98*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_ALLOC(&serv_buf, sizeof (struct servent), NSS_BUFLEN_SERVICES)
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate #ifdef PIC
101*7c478bd9Sstevel@tonic-gate #define	DOOR_GETHOSTBYNAME_R	_door_gethostbyname_r
102*7c478bd9Sstevel@tonic-gate #define	DOOR_GETHOSTBYADDR_R	_door_gethostbyaddr_r
103*7c478bd9Sstevel@tonic-gate #define	DOOR_GETIPNODEBYNAME_R	_door_getipnodebyname_r
104*7c478bd9Sstevel@tonic-gate #define	DOOR_GETIPNODEBYADDR_R	_door_getipnodebyaddr_r
105*7c478bd9Sstevel@tonic-gate #else
106*7c478bd9Sstevel@tonic-gate #define	DOOR_GETHOSTBYNAME_R	_switch_gethostbyname_r
107*7c478bd9Sstevel@tonic-gate #define	DOOR_GETHOSTBYADDR_R	_switch_gethostbyaddr_r
108*7c478bd9Sstevel@tonic-gate #define	DOOR_GETIPNODEBYNAME_R	_switch_getipnodebyname_r
109*7c478bd9Sstevel@tonic-gate #define	DOOR_GETIPNODEBYADDR_R	_switch_getipnodebyaddr_r
110*7c478bd9Sstevel@tonic-gate #endif /* PIC */
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate #define	DONT_SORT	"SORT_ADDRS=NO"
113*7c478bd9Sstevel@tonic-gate #define	DONT_SORT2	"SORT_ADDRS=FALSE"
114*7c478bd9Sstevel@tonic-gate #define	LINESIZE	100
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate /*
117*7c478bd9Sstevel@tonic-gate  * constant values of addresses for HOST_SELF_BIND, HOST_SELF_CONNECT
118*7c478bd9Sstevel@tonic-gate  * and localhost.
119*7c478bd9Sstevel@tonic-gate  *
120*7c478bd9Sstevel@tonic-gate  * The following variables are static to the extent that they should
121*7c478bd9Sstevel@tonic-gate  * not be visible outside of this file.
122*7c478bd9Sstevel@tonic-gate  */
123*7c478bd9Sstevel@tonic-gate static char *localaddr[] = {"\000\000\000\000", NULL};
124*7c478bd9Sstevel@tonic-gate static char *connectaddr[] = {"\177\000\000\001", NULL};
125*7c478bd9Sstevel@tonic-gate static char *localaddr6[] =
126*7c478bd9Sstevel@tonic-gate {"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", NULL};
127*7c478bd9Sstevel@tonic-gate static char *connectaddr6[] =
128*7c478bd9Sstevel@tonic-gate {"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001", NULL};
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate /* IPv4 nd_addrlist */
131*7c478bd9Sstevel@tonic-gate static mutex_t	nd_addr_lock = DEFAULTMUTEX;
132*7c478bd9Sstevel@tonic-gate static struct sockaddr_in sa_con;
133*7c478bd9Sstevel@tonic-gate static struct netbuf nd_conbuf = {sizeof (sa_con),\
134*7c478bd9Sstevel@tonic-gate     sizeof (sa_con), (char *)&sa_con};
135*7c478bd9Sstevel@tonic-gate static struct nd_addrlist nd_conaddrlist = {1, &nd_conbuf};
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate /* IPv6 nd_addrlist */
138*7c478bd9Sstevel@tonic-gate static mutex_t	nd6_addr_lock = DEFAULTMUTEX;
139*7c478bd9Sstevel@tonic-gate static struct sockaddr_in6 sa6_con;
140*7c478bd9Sstevel@tonic-gate static struct netbuf nd6_conbuf = {sizeof (sa6_con),\
141*7c478bd9Sstevel@tonic-gate 	sizeof (sa6_con), (char *)&sa6_con};
142*7c478bd9Sstevel@tonic-gate static struct nd_addrlist nd6_conaddrlist = {1, &nd6_conbuf};
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate #define	LOCALHOST "localhost"
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate struct servent *_switch_getservbyname_r(const char *, const char *,
147*7c478bd9Sstevel@tonic-gate     struct servent *, char *, int);
148*7c478bd9Sstevel@tonic-gate struct servent *_switch_getservbyport_r(int, const char *, struct servent *,
149*7c478bd9Sstevel@tonic-gate     char *, int);
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate static int __herrno2netdir(int h_errnop);
152*7c478bd9Sstevel@tonic-gate static struct ifinfo *get_local_info(void);
153*7c478bd9Sstevel@tonic-gate static int islocal();
154*7c478bd9Sstevel@tonic-gate static int getbroadcastnets(struct netconfig *, struct in_addr **);
155*7c478bd9Sstevel@tonic-gate static int hent2ndaddr(int, char **, int *, struct nd_addrlist **);
156*7c478bd9Sstevel@tonic-gate static int ndaddr2hent(int, const char *, struct nd_addrlist *,
157*7c478bd9Sstevel@tonic-gate     struct hostent *, char *, int);
158*7c478bd9Sstevel@tonic-gate static int hsents2ndhostservs(struct hostent *, struct servent *, ushort_t,
159*7c478bd9Sstevel@tonic-gate     struct nd_hostservlist **);
160*7c478bd9Sstevel@tonic-gate static int ndaddr2srent(const char *, const char *, ushort_t, struct servent *,
161*7c478bd9Sstevel@tonic-gate     char *, int);
162*7c478bd9Sstevel@tonic-gate static int ndhostserv2hent(struct netbuf *, struct nd_hostservlist *,
163*7c478bd9Sstevel@tonic-gate     struct hostent *, char *, int);
164*7c478bd9Sstevel@tonic-gate static int ndhostserv2srent(int, const char *, struct nd_hostservlist *,
165*7c478bd9Sstevel@tonic-gate     struct servent *, char *, int);
166*7c478bd9Sstevel@tonic-gate static int nd2herrno(int nerr);
167*7c478bd9Sstevel@tonic-gate static void order_haddrlist_inet(char **haddrlist, size_t addrcount);
168*7c478bd9Sstevel@tonic-gate static void order_haddrlist_inet6(char **haddrlist, size_t addrcount);
169*7c478bd9Sstevel@tonic-gate static int dstcmp(const void *, const void *);
170*7c478bd9Sstevel@tonic-gate static int nss_strioctl(int af, int cmd, void *ptr, int ilen);
171*7c478bd9Sstevel@tonic-gate static struct in_addr _inet_makeaddr(in_addr_t, in_addr_t);
172*7c478bd9Sstevel@tonic-gate static boolean_t _read_nsw_file(void);
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate /*
175*7c478bd9Sstevel@tonic-gate  * Begin: PART I
176*7c478bd9Sstevel@tonic-gate  * Top Level Interfaces that gethost/serv/netdir funnel through.
177*7c478bd9Sstevel@tonic-gate  */
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate /*
180*7c478bd9Sstevel@tonic-gate  * gethost/servbyname always call this function; if they call
181*7c478bd9Sstevel@tonic-gate  * with nametoaddr libs in nconf, we call netdir_getbyname
182*7c478bd9Sstevel@tonic-gate  * implementation: __classic_netdir_getbyname, otherwise nsswitch.
183*7c478bd9Sstevel@tonic-gate  *
184*7c478bd9Sstevel@tonic-gate  * netdir_getbyname calls this only if nametoaddr libs are NOT
185*7c478bd9Sstevel@tonic-gate  * specified for inet transports; i.e. it's supposed to follow
186*7c478bd9Sstevel@tonic-gate  * the name service switch.
187*7c478bd9Sstevel@tonic-gate  */
188*7c478bd9Sstevel@tonic-gate int
189*7c478bd9Sstevel@tonic-gate _get_hostserv_inetnetdir_byname(struct netconfig *nconf,
190*7c478bd9Sstevel@tonic-gate     struct nss_netdirbyname_in *args, union nss_netdirbyname_out *res)
191*7c478bd9Sstevel@tonic-gate {
192*7c478bd9Sstevel@tonic-gate 	int	server_port;
193*7c478bd9Sstevel@tonic-gate 	int *servp = &server_port;
194*7c478bd9Sstevel@tonic-gate 	char	**haddrlist;
195*7c478bd9Sstevel@tonic-gate 	uint32_t dotnameaddr;
196*7c478bd9Sstevel@tonic-gate 	char	*dotnamelist[2];
197*7c478bd9Sstevel@tonic-gate 	struct in_addr	*inaddrs = NULL;
198*7c478bd9Sstevel@tonic-gate 	struct in6_addr	v6nameaddr;
199*7c478bd9Sstevel@tonic-gate 	char	**baddrlist = NULL;
200*7c478bd9Sstevel@tonic-gate 	extern	int _inet_aton();
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	if (nconf == NULL) {
204*7c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
205*7c478bd9Sstevel@tonic-gate 		return (ND_BADARG);
206*7c478bd9Sstevel@tonic-gate 	}
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	/*
209*7c478bd9Sstevel@tonic-gate 	 * 1. gethostbyname()/netdir_getbyname() special cases:
210*7c478bd9Sstevel@tonic-gate 	 */
211*7c478bd9Sstevel@tonic-gate 	switch (args->op_t) {
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 		case NSS_HOST:
214*7c478bd9Sstevel@tonic-gate 		/*
215*7c478bd9Sstevel@tonic-gate 		 * Worth the performance gain -- assuming a lot of inet apps
216*7c478bd9Sstevel@tonic-gate 		 * actively use "localhost".
217*7c478bd9Sstevel@tonic-gate 		 */
218*7c478bd9Sstevel@tonic-gate 		if (strcmp(args->arg.nss.host.name, LOCALHOST) == 0) {
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 			mutex_lock(&nd_addr_lock);
221*7c478bd9Sstevel@tonic-gate 			IN_SET_LOOPBACK_ADDR(&sa_con);
222*7c478bd9Sstevel@tonic-gate 			_nderror = ndaddr2hent(AF_INET, args->arg.nss.host.name,
223*7c478bd9Sstevel@tonic-gate 			    &nd_conaddrlist, res->nss.host.hent,
224*7c478bd9Sstevel@tonic-gate 			    args->arg.nss.host.buf,
225*7c478bd9Sstevel@tonic-gate 			    args->arg.nss.host.buflen);
226*7c478bd9Sstevel@tonic-gate 			mutex_unlock(&nd_addr_lock);
227*7c478bd9Sstevel@tonic-gate 			if (_nderror != ND_OK)
228*7c478bd9Sstevel@tonic-gate 				*(res->nss.host.herrno_p) =
229*7c478bd9Sstevel@tonic-gate 				    nd2herrno(_nderror);
230*7c478bd9Sstevel@tonic-gate 			return (_nderror);
231*7c478bd9Sstevel@tonic-gate 		}
232*7c478bd9Sstevel@tonic-gate 		/*
233*7c478bd9Sstevel@tonic-gate 		 * If the caller passed in a dot separated IP notation to
234*7c478bd9Sstevel@tonic-gate 		 * gethostbyname, return that back as the address.
235*7c478bd9Sstevel@tonic-gate 		 * The nd_addr_lock mutex was added to be truely re-entrant.
236*7c478bd9Sstevel@tonic-gate 		 */
237*7c478bd9Sstevel@tonic-gate 		if (_inet_aton(args->arg.nss.host.name,
238*7c478bd9Sstevel@tonic-gate 		    (struct in_addr *)&dotnameaddr)) {
239*7c478bd9Sstevel@tonic-gate 			mutex_lock(&nd_addr_lock);
240*7c478bd9Sstevel@tonic-gate 			(void) memset((char *)&sa_con, 0, sizeof (sa_con));
241*7c478bd9Sstevel@tonic-gate 			sa_con.sin_family = AF_INET;
242*7c478bd9Sstevel@tonic-gate 			sa_con.sin_addr.s_addr = dotnameaddr;
243*7c478bd9Sstevel@tonic-gate 			_nderror = ndaddr2hent(AF_INET, args->arg.nss.host.name,
244*7c478bd9Sstevel@tonic-gate 			    &nd_conaddrlist, res->nss.host.hent,
245*7c478bd9Sstevel@tonic-gate 			    args->arg.nss.host.buf,
246*7c478bd9Sstevel@tonic-gate 			    args->arg.nss.host.buflen);
247*7c478bd9Sstevel@tonic-gate 			mutex_unlock(&nd_addr_lock);
248*7c478bd9Sstevel@tonic-gate 			if (_nderror != ND_OK)
249*7c478bd9Sstevel@tonic-gate 				*(res->nss.host.herrno_p) =
250*7c478bd9Sstevel@tonic-gate 				    nd2herrno(_nderror);
251*7c478bd9Sstevel@tonic-gate 			return (_nderror);
252*7c478bd9Sstevel@tonic-gate 		}
253*7c478bd9Sstevel@tonic-gate 		break;
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 		case NSS_HOST6:
256*7c478bd9Sstevel@tonic-gate 		/*
257*7c478bd9Sstevel@tonic-gate 		 * Handle case of literal address string.
258*7c478bd9Sstevel@tonic-gate 		 */
259*7c478bd9Sstevel@tonic-gate 		if (strchr(args->arg.nss.host6.name, ':') != NULL &&
260*7c478bd9Sstevel@tonic-gate 		    (inet_pton(AF_INET6, args->arg.nss.host6.name,
261*7c478bd9Sstevel@tonic-gate 		    &v6nameaddr) != 0)) {
262*7c478bd9Sstevel@tonic-gate 			int	ret;
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 			mutex_lock(&nd6_addr_lock);
265*7c478bd9Sstevel@tonic-gate 			(void) memset((char *)&sa6_con, 0, sizeof (sa6_con));
266*7c478bd9Sstevel@tonic-gate 			sa6_con.sin6_family = AF_INET6;
267*7c478bd9Sstevel@tonic-gate 			memcpy((char *)&(sa6_con.sin6_addr.s6_addr),
268*7c478bd9Sstevel@tonic-gate 			    &v6nameaddr, sizeof (struct in6_addr));
269*7c478bd9Sstevel@tonic-gate 			ret = ndaddr2hent(AF_INET6,
270*7c478bd9Sstevel@tonic-gate 			    args->arg.nss.host6.name,
271*7c478bd9Sstevel@tonic-gate 			    &nd6_conaddrlist, res->nss.host.hent,
272*7c478bd9Sstevel@tonic-gate 			    args->arg.nss.host6.buf,
273*7c478bd9Sstevel@tonic-gate 			    args->arg.nss.host6.buflen);
274*7c478bd9Sstevel@tonic-gate 			mutex_unlock(&nd6_addr_lock);
275*7c478bd9Sstevel@tonic-gate 			if (ret != ND_OK)
276*7c478bd9Sstevel@tonic-gate 				*(res->nss.host.herrno_p) = nd2herrno(ret);
277*7c478bd9Sstevel@tonic-gate 			else
278*7c478bd9Sstevel@tonic-gate 				res->nss.host.hent->h_aliases = NULL;
279*7c478bd9Sstevel@tonic-gate 			return (ret);
280*7c478bd9Sstevel@tonic-gate 		}
281*7c478bd9Sstevel@tonic-gate 		break;
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 		case NETDIR_BY:
284*7c478bd9Sstevel@tonic-gate 			if (args->arg.nd_hs == 0) {
285*7c478bd9Sstevel@tonic-gate 				_nderror = ND_BADARG;
286*7c478bd9Sstevel@tonic-gate 				return (ND_BADARG);
287*7c478bd9Sstevel@tonic-gate 			}
288*7c478bd9Sstevel@tonic-gate 			/*
289*7c478bd9Sstevel@tonic-gate 			 * If servname is NULL, return 0 as the port number
290*7c478bd9Sstevel@tonic-gate 			 * If servname is rpcbind, return 111 as the port number
291*7c478bd9Sstevel@tonic-gate 			 * If servname is a number, return it back as the port
292*7c478bd9Sstevel@tonic-gate 			 * number.
293*7c478bd9Sstevel@tonic-gate 			 */
294*7c478bd9Sstevel@tonic-gate 			if (args->arg.nd_hs->h_serv == 0) {
295*7c478bd9Sstevel@tonic-gate 				*servp = htons(0);
296*7c478bd9Sstevel@tonic-gate 			} else if (strcmp(args->arg.nd_hs->h_serv, "rpcbind")
297*7c478bd9Sstevel@tonic-gate 									== 0) {
298*7c478bd9Sstevel@tonic-gate 				*servp = htons(111);
299*7c478bd9Sstevel@tonic-gate 			} else if (strspn(args->arg.nd_hs->h_serv, "0123456789")
300*7c478bd9Sstevel@tonic-gate 				    == strlen(args->arg.nd_hs->h_serv)) {
301*7c478bd9Sstevel@tonic-gate 				*servp = htons(atoi(args->arg.nd_hs->h_serv));
302*7c478bd9Sstevel@tonic-gate 			} else {
303*7c478bd9Sstevel@tonic-gate 				/* i.e. need to call a name service on this */
304*7c478bd9Sstevel@tonic-gate 				servp = NULL;
305*7c478bd9Sstevel@tonic-gate 			}
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 			/*
308*7c478bd9Sstevel@tonic-gate 			 * If the hostname is HOST_SELF_BIND, we return 0.0.0.0
309*7c478bd9Sstevel@tonic-gate 			 * so the  binding can be contacted through all
310*7c478bd9Sstevel@tonic-gate 			 * interfaces. If the hostname is HOST_SELF_CONNECT,
311*7c478bd9Sstevel@tonic-gate 			 * we return 127.0.0.1 so the address can be connected
312*7c478bd9Sstevel@tonic-gate 			 * to locally. If the hostname is HOST_ANY, we return
313*7c478bd9Sstevel@tonic-gate 			 * no addresses because IP doesn't know how to specify
314*7c478bd9Sstevel@tonic-gate 			 * a service without a host. And finally if we specify
315*7c478bd9Sstevel@tonic-gate 			 * HOST_BROADCAST then we ask a tli fd to tell us what
316*7c478bd9Sstevel@tonic-gate 			 * the broadcast addresses are for any udp
317*7c478bd9Sstevel@tonic-gate 			 * interfaces on this machine.
318*7c478bd9Sstevel@tonic-gate 			 */
319*7c478bd9Sstevel@tonic-gate 			if (args->arg.nd_hs->h_host == 0) {
320*7c478bd9Sstevel@tonic-gate 				_nderror = ND_NOHOST;
321*7c478bd9Sstevel@tonic-gate 				return (ND_NOHOST);
322*7c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
323*7c478bd9Sstevel@tonic-gate 			    HOST_SELF_BIND) == 0)) {
324*7c478bd9Sstevel@tonic-gate 				haddrlist = localaddr;
325*7c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
326*7c478bd9Sstevel@tonic-gate 					    HOST_SELF_CONNECT) == 0)) {
327*7c478bd9Sstevel@tonic-gate 				haddrlist = connectaddr;
328*7c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
329*7c478bd9Sstevel@tonic-gate 					    LOCALHOST) == 0)) {
330*7c478bd9Sstevel@tonic-gate 				haddrlist = connectaddr;
331*7c478bd9Sstevel@tonic-gate 			} else if ((int)(dotnameaddr =
332*7c478bd9Sstevel@tonic-gate 				    inet_addr(args->arg.nd_hs->h_host)) != -1) {
333*7c478bd9Sstevel@tonic-gate 				/*
334*7c478bd9Sstevel@tonic-gate 				 * If the caller passed in a dot separated IP
335*7c478bd9Sstevel@tonic-gate 				 * notation to netdir_getbyname, convert that
336*7c478bd9Sstevel@tonic-gate 				 * back into address.
337*7c478bd9Sstevel@tonic-gate 				 */
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 				dotnamelist[0] = (char *)&dotnameaddr;
340*7c478bd9Sstevel@tonic-gate 				dotnamelist[1] = NULL;
341*7c478bd9Sstevel@tonic-gate 				haddrlist = dotnamelist;
342*7c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
343*7c478bd9Sstevel@tonic-gate 					    HOST_BROADCAST) == 0)) {
344*7c478bd9Sstevel@tonic-gate 				/*
345*7c478bd9Sstevel@tonic-gate 				 * Now that inaddrs and baddrlist are
346*7c478bd9Sstevel@tonic-gate 				 * dynamically allocated, care must be
347*7c478bd9Sstevel@tonic-gate 				 * taken in freeing up the
348*7c478bd9Sstevel@tonic-gate 				 * memory at each 'return()' point.
349*7c478bd9Sstevel@tonic-gate 				 *
350*7c478bd9Sstevel@tonic-gate 				 * Early return protection (using
351*7c478bd9Sstevel@tonic-gate 				 * FREE_return()) is needed only in NETDIR_BY
352*7c478bd9Sstevel@tonic-gate 				 * cases because dynamic allocation is used
353*7c478bd9Sstevel@tonic-gate 				 * when args->op_t == NETDIR_BY.
354*7c478bd9Sstevel@tonic-gate 				 *
355*7c478bd9Sstevel@tonic-gate 				 * Early return protection is not needed in
356*7c478bd9Sstevel@tonic-gate 				 * haddrlist==0 conditionals because dynamic
357*7c478bd9Sstevel@tonic-gate 				 * allocation guarantees haddrlist!=0.
358*7c478bd9Sstevel@tonic-gate 				 *
359*7c478bd9Sstevel@tonic-gate 				 * Early return protection is not needed in most
360*7c478bd9Sstevel@tonic-gate 				 * servp!=0 conditionals because this is handled
361*7c478bd9Sstevel@tonic-gate 				 * (and returned) first.
362*7c478bd9Sstevel@tonic-gate 				 */
363*7c478bd9Sstevel@tonic-gate #define	FREE_return(ret) \
364*7c478bd9Sstevel@tonic-gate 				{ \
365*7c478bd9Sstevel@tonic-gate 				    if (inaddrs) \
366*7c478bd9Sstevel@tonic-gate 					    free(inaddrs); \
367*7c478bd9Sstevel@tonic-gate 					    if (baddrlist) \
368*7c478bd9Sstevel@tonic-gate 						    free(baddrlist); \
369*7c478bd9Sstevel@tonic-gate 						    _nderror = ret; \
370*7c478bd9Sstevel@tonic-gate 						    return (ret); \
371*7c478bd9Sstevel@tonic-gate 				}
372*7c478bd9Sstevel@tonic-gate 				int i, bnets;
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 				bnets = getbroadcastnets(nconf, &inaddrs);
375*7c478bd9Sstevel@tonic-gate 				if (bnets == 0) {
376*7c478bd9Sstevel@tonic-gate 					_nderror = ND_NOHOST;
377*7c478bd9Sstevel@tonic-gate 					return (ND_NOHOST);
378*7c478bd9Sstevel@tonic-gate 				}
379*7c478bd9Sstevel@tonic-gate 				baddrlist =
380*7c478bd9Sstevel@tonic-gate 				    (char **)malloc((bnets+1)*sizeof (char *));
381*7c478bd9Sstevel@tonic-gate 				if (baddrlist == NULL)
382*7c478bd9Sstevel@tonic-gate 					FREE_return(ND_NOMEM);
383*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < bnets; i++)
384*7c478bd9Sstevel@tonic-gate 					baddrlist[i] = (char *)&inaddrs[i];
385*7c478bd9Sstevel@tonic-gate 				baddrlist[i] = NULL;
386*7c478bd9Sstevel@tonic-gate 				haddrlist = baddrlist;
387*7c478bd9Sstevel@tonic-gate 			} else {
388*7c478bd9Sstevel@tonic-gate 				/* i.e. need to call a name service on this */
389*7c478bd9Sstevel@tonic-gate 				haddrlist = 0;
390*7c478bd9Sstevel@tonic-gate 			}
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 			if (haddrlist && servp) {
393*7c478bd9Sstevel@tonic-gate 				int ret;
394*7c478bd9Sstevel@tonic-gate 				/*
395*7c478bd9Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
396*7c478bd9Sstevel@tonic-gate 				 * malloc's will be done, freed using
397*7c478bd9Sstevel@tonic-gate 				 * netdir_free.
398*7c478bd9Sstevel@tonic-gate 				 */
399*7c478bd9Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET, haddrlist, servp,
400*7c478bd9Sstevel@tonic-gate 					    res->nd_alist);
401*7c478bd9Sstevel@tonic-gate 				FREE_return(ret)
402*7c478bd9Sstevel@tonic-gate 				}
403*7c478bd9Sstevel@tonic-gate 			break;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 		case NETDIR_BY6:
407*7c478bd9Sstevel@tonic-gate 			if (args->arg.nd_hs == 0) {
408*7c478bd9Sstevel@tonic-gate 				_nderror = ND_BADARG;
409*7c478bd9Sstevel@tonic-gate 				return (ND_BADARG);
410*7c478bd9Sstevel@tonic-gate 			}
411*7c478bd9Sstevel@tonic-gate 			/*
412*7c478bd9Sstevel@tonic-gate 			 * If servname is NULL, return 0 as the port number.
413*7c478bd9Sstevel@tonic-gate 			 * If servname is rpcbind, return 111 as the port number
414*7c478bd9Sstevel@tonic-gate 			 * If servname is a number, return it back as the port
415*7c478bd9Sstevel@tonic-gate 			 * number.
416*7c478bd9Sstevel@tonic-gate 			 */
417*7c478bd9Sstevel@tonic-gate 			if (args->arg.nd_hs->h_serv == 0) {
418*7c478bd9Sstevel@tonic-gate 				*servp = htons(0);
419*7c478bd9Sstevel@tonic-gate 			} else if (strcmp(args->arg.nd_hs->h_serv,
420*7c478bd9Sstevel@tonic-gate 				    "rpcbind") == 0) {
421*7c478bd9Sstevel@tonic-gate 				*servp = htons(111);
422*7c478bd9Sstevel@tonic-gate 			} else if (strspn(args->arg.nd_hs->h_serv, "0123456789")
423*7c478bd9Sstevel@tonic-gate 				    == strlen(args->arg.nd_hs->h_serv)) {
424*7c478bd9Sstevel@tonic-gate 				*servp = htons(atoi(args->arg.nd_hs->h_serv));
425*7c478bd9Sstevel@tonic-gate 			} else {
426*7c478bd9Sstevel@tonic-gate 				/* i.e. need to call a name service on this */
427*7c478bd9Sstevel@tonic-gate 				servp = NULL;
428*7c478bd9Sstevel@tonic-gate 			}
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 			/*
431*7c478bd9Sstevel@tonic-gate 			 * If the hostname is HOST_SELF_BIND, we return ipv6
432*7c478bd9Sstevel@tonic-gate 			 * localaddress so the binding can be contacted through
433*7c478bd9Sstevel@tonic-gate 			 * all interfaces.
434*7c478bd9Sstevel@tonic-gate 			 * If the hostname is HOST_SELF_CONNECT, we return
435*7c478bd9Sstevel@tonic-gate 			 * ipv6 loopback address so the address can be connected
436*7c478bd9Sstevel@tonic-gate 			 * to locally.
437*7c478bd9Sstevel@tonic-gate 			 * If the hostname is HOST_ANY, we return no addresses
438*7c478bd9Sstevel@tonic-gate 			 * because IP doesn't know how to specify a service
439*7c478bd9Sstevel@tonic-gate 			 * without a host.
440*7c478bd9Sstevel@tonic-gate 			 * And finally if we specify HOST_BROADCAST then we
441*7c478bd9Sstevel@tonic-gate 			 * disallow since IPV6 does not have any
442*7c478bd9Sstevel@tonic-gate 			 * broadcast concept.
443*7c478bd9Sstevel@tonic-gate 			 */
444*7c478bd9Sstevel@tonic-gate 			if (args->arg.nd_hs->h_host == 0) {
445*7c478bd9Sstevel@tonic-gate 				return (ND_NOHOST);
446*7c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
447*7c478bd9Sstevel@tonic-gate 					    HOST_SELF_BIND) == 0)) {
448*7c478bd9Sstevel@tonic-gate 				haddrlist = localaddr6;
449*7c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
450*7c478bd9Sstevel@tonic-gate 					    HOST_SELF_CONNECT) == 0)) {
451*7c478bd9Sstevel@tonic-gate 				haddrlist = connectaddr6;
452*7c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
453*7c478bd9Sstevel@tonic-gate 					    LOCALHOST) == 0)) {
454*7c478bd9Sstevel@tonic-gate 				haddrlist = connectaddr6;
455*7c478bd9Sstevel@tonic-gate 			} else if (strchr(args->arg.nd_hs->h_host, ':')
456*7c478bd9Sstevel@tonic-gate 						    != NULL) {
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 			/*
459*7c478bd9Sstevel@tonic-gate 			 * If the caller passed in a dot separated IP notation
460*7c478bd9Sstevel@tonic-gate 			 * to netdir_getbyname, convert that back into address.
461*7c478bd9Sstevel@tonic-gate 			 */
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 				if ((inet_pton(AF_INET6,
464*7c478bd9Sstevel@tonic-gate 					    args->arg.nd_hs->h_host,
465*7c478bd9Sstevel@tonic-gate 					    &v6nameaddr)) != 0) {
466*7c478bd9Sstevel@tonic-gate 					dotnamelist[0] = (char *)&v6nameaddr;
467*7c478bd9Sstevel@tonic-gate 					dotnamelist[1] = NULL;
468*7c478bd9Sstevel@tonic-gate 					haddrlist = dotnamelist;
469*7c478bd9Sstevel@tonic-gate 				}
470*7c478bd9Sstevel@tonic-gate 				else
471*7c478bd9Sstevel@tonic-gate 					/* not sure what to return */
472*7c478bd9Sstevel@tonic-gate 					return (ND_NOHOST);
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
475*7c478bd9Sstevel@tonic-gate 				    HOST_BROADCAST) == 0)) {
476*7c478bd9Sstevel@tonic-gate 				/*
477*7c478bd9Sstevel@tonic-gate 				 * Don't support broadcast in
478*7c478bd9Sstevel@tonic-gate 				 * IPV6
479*7c478bd9Sstevel@tonic-gate 				 */
480*7c478bd9Sstevel@tonic-gate 				return (ND_NOHOST);
481*7c478bd9Sstevel@tonic-gate 			} else {
482*7c478bd9Sstevel@tonic-gate 				/* i.e. need to call a name service on this */
483*7c478bd9Sstevel@tonic-gate 				haddrlist = 0;
484*7c478bd9Sstevel@tonic-gate 			}
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 			if (haddrlist && servp) {
487*7c478bd9Sstevel@tonic-gate 				int ret;
488*7c478bd9Sstevel@tonic-gate 				/*
489*7c478bd9Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
490*7c478bd9Sstevel@tonic-gate 				 * malloc's will be done, freed
491*7c478bd9Sstevel@tonic-gate 				 * using netdir_free.
492*7c478bd9Sstevel@tonic-gate 				 */
493*7c478bd9Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET6, haddrlist,
494*7c478bd9Sstevel@tonic-gate 				    servp, res->nd_alist);
495*7c478bd9Sstevel@tonic-gate 				FREE_return(ret)
496*7c478bd9Sstevel@tonic-gate 				}
497*7c478bd9Sstevel@tonic-gate 			break;
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 	}
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	/*
503*7c478bd9Sstevel@tonic-gate 	 * 2. Most common scenario. This is the way we ship /etc/netconfig.
504*7c478bd9Sstevel@tonic-gate 	 *    Emphasis on improving performance in the "if" part.
505*7c478bd9Sstevel@tonic-gate 	 */
506*7c478bd9Sstevel@tonic-gate 	if (nconf->nc_nlookups == 0) {
507*7c478bd9Sstevel@tonic-gate 		struct hostent	*he = NULL, *tmphe;
508*7c478bd9Sstevel@tonic-gate 		struct servent	*se;
509*7c478bd9Sstevel@tonic-gate 		int	ret;
510*7c478bd9Sstevel@tonic-gate 		nss_XbyY_buf_t	*ndbuf4switch = 0;
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	switch (args->op_t) {
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 		case NSS_HOST:
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 		he = DOOR_GETHOSTBYNAME_R(args->arg.nss.host.name,
517*7c478bd9Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
518*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.buflen,
519*7c478bd9Sstevel@tonic-gate 		    res->nss.host.herrno_p);
520*7c478bd9Sstevel@tonic-gate 		if (he == NULL)
521*7c478bd9Sstevel@tonic-gate 			return (_nderror = ND_NOHOST);
522*7c478bd9Sstevel@tonic-gate 		return (_nderror = ND_OK);
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 		case NSS_HOST6:
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 		he = DOOR_GETIPNODEBYNAME_R(args->arg.nss.host6.name,
527*7c478bd9Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
528*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.host6.buflen,
529*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.host6.af_family,
530*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.host6.flags,
531*7c478bd9Sstevel@tonic-gate 		    res->nss.host.herrno_p);
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 		if (he == NULL) {
534*7c478bd9Sstevel@tonic-gate 			trace1(TR__get_hostserv_inetnetdir_byname, 12);
535*7c478bd9Sstevel@tonic-gate 			return (_nderror = ND_NOHOST);
536*7c478bd9Sstevel@tonic-gate 		}
537*7c478bd9Sstevel@tonic-gate 		return (_nderror = ND_OK);
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 		case NSS_SERV:
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 		se = _switch_getservbyname_r(args->arg.nss.serv.name,
542*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.proto,
543*7c478bd9Sstevel@tonic-gate 		    res->nss.serv, args->arg.nss.serv.buf,
544*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.buflen);
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 		_nderror = ND_OK;
547*7c478bd9Sstevel@tonic-gate 		if (se == 0)
548*7c478bd9Sstevel@tonic-gate 			_nderror = ND_NOSERV;
549*7c478bd9Sstevel@tonic-gate 		return (_nderror);
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 		case NETDIR_BY:
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 		if (servp == 0) {
554*7c478bd9Sstevel@tonic-gate 			char	*proto =
555*7c478bd9Sstevel@tonic-gate 	    (strcmp(nconf->nc_proto, NC_TCP) == 0) ? NC_TCP : NC_UDP;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 			/*
558*7c478bd9Sstevel@tonic-gate 			 * We go through all this for just one port number,
559*7c478bd9Sstevel@tonic-gate 			 * which is most often constant. How about linking in
560*7c478bd9Sstevel@tonic-gate 			 * an indexed database of well-known ports in the name
561*7c478bd9Sstevel@tonic-gate 			 * of performance ?
562*7c478bd9Sstevel@tonic-gate 			 */
563*7c478bd9Sstevel@tonic-gate 			GETSERVBUF(ndbuf4switch);
564*7c478bd9Sstevel@tonic-gate 			if (ndbuf4switch == 0)
565*7c478bd9Sstevel@tonic-gate 				FREE_return(ND_NOMEM);
566*7c478bd9Sstevel@tonic-gate 			se = _switch_getservbyname_r(args->arg.nd_hs->h_serv,
567*7c478bd9Sstevel@tonic-gate 				proto, ndbuf4switch->result,
568*7c478bd9Sstevel@tonic-gate 				ndbuf4switch->buffer, ndbuf4switch->buflen);
569*7c478bd9Sstevel@tonic-gate 			if (!se) {
570*7c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4switch);
571*7c478bd9Sstevel@tonic-gate 				FREE_return(ND_NOSERV)
572*7c478bd9Sstevel@tonic-gate 			}
573*7c478bd9Sstevel@tonic-gate 			server_port = se->s_port;
574*7c478bd9Sstevel@tonic-gate 			NSS_XbyY_FREE(&ndbuf4switch);
575*7c478bd9Sstevel@tonic-gate 		}
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 		if (haddrlist == 0) {
578*7c478bd9Sstevel@tonic-gate 			int	h_errnop = 0;
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 			GETHOSTBUF(ndbuf4switch);
581*7c478bd9Sstevel@tonic-gate 			if (ndbuf4switch == 0) {
582*7c478bd9Sstevel@tonic-gate 				_nderror = ND_NOMEM;
583*7c478bd9Sstevel@tonic-gate 				return (ND_NOMEM);
584*7c478bd9Sstevel@tonic-gate 			}
585*7c478bd9Sstevel@tonic-gate 			/*
586*7c478bd9Sstevel@tonic-gate 			 * Search the ipnodes (v6) path first,
587*7c478bd9Sstevel@tonic-gate 			 * search will return the v4 addresses
588*7c478bd9Sstevel@tonic-gate 			 * as v4mapped addresses.
589*7c478bd9Sstevel@tonic-gate 			 */
590*7c478bd9Sstevel@tonic-gate 			if ((tmphe = DOOR_GETIPNODEBYNAME_R(
591*7c478bd9Sstevel@tonic-gate 			    args->arg.nd_hs->h_host,
592*7c478bd9Sstevel@tonic-gate 			    ndbuf4switch->result, ndbuf4switch->buffer,
593*7c478bd9Sstevel@tonic-gate 			    ndbuf4switch->buflen, args->arg.nss.host6.af_family,
594*7c478bd9Sstevel@tonic-gate 			    args->arg.nss.host6.flags, &h_errnop)) != NULL)
595*7c478bd9Sstevel@tonic-gate 				he = __mappedtov4(tmphe, &h_errnop);
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 			if (he == NULL) {
598*7c478bd9Sstevel@tonic-gate 				/* Failover case, try hosts db for v4 address */
599*7c478bd9Sstevel@tonic-gate 				he = DOOR_GETHOSTBYNAME_R(
600*7c478bd9Sstevel@tonic-gate 				args->arg.nd_hs->h_host,
601*7c478bd9Sstevel@tonic-gate 				ndbuf4switch->result, ndbuf4switch->buffer,
602*7c478bd9Sstevel@tonic-gate 				ndbuf4switch->buflen, &h_errnop);
603*7c478bd9Sstevel@tonic-gate 				if (he == NULL) {
604*7c478bd9Sstevel@tonic-gate 					NSS_XbyY_FREE(&ndbuf4switch);
605*7c478bd9Sstevel@tonic-gate 					_nderror = h_errnop ?
606*7c478bd9Sstevel@tonic-gate 					    __herrno2netdir(h_errnop) :
607*7c478bd9Sstevel@tonic-gate 					    ND_NOHOST;
608*7c478bd9Sstevel@tonic-gate 					return (_nderror);
609*7c478bd9Sstevel@tonic-gate 				}
610*7c478bd9Sstevel@tonic-gate 				/*
611*7c478bd9Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
612*7c478bd9Sstevel@tonic-gate 				 * malloc's will be done, freed using
613*7c478bd9Sstevel@tonic-gate 				 * netdir_free.
614*7c478bd9Sstevel@tonic-gate 				 */
615*7c478bd9Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET, he->h_addr_list,
616*7c478bd9Sstevel@tonic-gate 					&server_port, res->nd_alist);
617*7c478bd9Sstevel@tonic-gate 			} else {
618*7c478bd9Sstevel@tonic-gate 				/*
619*7c478bd9Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
620*7c478bd9Sstevel@tonic-gate 				 * malloc's will be done, freed using
621*7c478bd9Sstevel@tonic-gate 				 * netdir_free.
622*7c478bd9Sstevel@tonic-gate 				 */
623*7c478bd9Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET, he->h_addr_list,
624*7c478bd9Sstevel@tonic-gate 					&server_port, res->nd_alist);
625*7c478bd9Sstevel@tonic-gate 				freehostent(he);
626*7c478bd9Sstevel@tonic-gate 			}
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 			_nderror = ret;
629*7c478bd9Sstevel@tonic-gate 			NSS_XbyY_FREE(&ndbuf4switch);
630*7c478bd9Sstevel@tonic-gate 			return (ret);
631*7c478bd9Sstevel@tonic-gate 		} else {
632*7c478bd9Sstevel@tonic-gate 			int ret;
633*7c478bd9Sstevel@tonic-gate 			/*
634*7c478bd9Sstevel@tonic-gate 			 * Convert h_addr_list into nd_addrlist.
635*7c478bd9Sstevel@tonic-gate 			 * malloc's will be done, freed using netdir_free.
636*7c478bd9Sstevel@tonic-gate 			 */
637*7c478bd9Sstevel@tonic-gate 			ret = hent2ndaddr(AF_INET, haddrlist,
638*7c478bd9Sstevel@tonic-gate 				    &server_port, res->nd_alist);
639*7c478bd9Sstevel@tonic-gate 			FREE_return(ret)
640*7c478bd9Sstevel@tonic-gate 		}
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 		case NETDIR_BY6:
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 			if (servp == 0) {
646*7c478bd9Sstevel@tonic-gate 				char	*proto =
647*7c478bd9Sstevel@tonic-gate 	(strcmp(nconf->nc_proto, NC_TCP) == 0) ? NC_TCP : NC_UDP;
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 				/*
650*7c478bd9Sstevel@tonic-gate 				 * We go through all this for just
651*7c478bd9Sstevel@tonic-gate 				 * one port number,
652*7c478bd9Sstevel@tonic-gate 				 * which is most often constant.
653*7c478bd9Sstevel@tonic-gate 				 * How about linking in
654*7c478bd9Sstevel@tonic-gate 				 * an indexed database of well-known
655*7c478bd9Sstevel@tonic-gate 				 * ports in the name
656*7c478bd9Sstevel@tonic-gate 				 * of performance ?
657*7c478bd9Sstevel@tonic-gate 				 */
658*7c478bd9Sstevel@tonic-gate 				GETSERVBUF(ndbuf4switch);
659*7c478bd9Sstevel@tonic-gate 				if (ndbuf4switch == 0)
660*7c478bd9Sstevel@tonic-gate 					FREE_return(ND_NOMEM);
661*7c478bd9Sstevel@tonic-gate 				se = _switch_getservbyname_r(
662*7c478bd9Sstevel@tonic-gate 					    args->arg.nd_hs->h_serv,
663*7c478bd9Sstevel@tonic-gate 				    proto, ndbuf4switch->result,
664*7c478bd9Sstevel@tonic-gate 				    ndbuf4switch->buffer, ndbuf4switch->buflen);
665*7c478bd9Sstevel@tonic-gate 				if (!se) {
666*7c478bd9Sstevel@tonic-gate 					NSS_XbyY_FREE(&ndbuf4switch);
667*7c478bd9Sstevel@tonic-gate 					FREE_return(ND_NOSERV)
668*7c478bd9Sstevel@tonic-gate 				}
669*7c478bd9Sstevel@tonic-gate 				server_port = se->s_port;
670*7c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4switch);
671*7c478bd9Sstevel@tonic-gate 			}
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 			if (haddrlist == 0) {
674*7c478bd9Sstevel@tonic-gate 				int	h_errnop = 0;
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate 				GETHOSTBUF(ndbuf4switch);
677*7c478bd9Sstevel@tonic-gate 				if (ndbuf4switch == 0) {
678*7c478bd9Sstevel@tonic-gate 					_nderror = ND_NOMEM;
679*7c478bd9Sstevel@tonic-gate 					return (ND_NOMEM);
680*7c478bd9Sstevel@tonic-gate 				}
681*7c478bd9Sstevel@tonic-gate 				he = DOOR_GETIPNODEBYNAME_R(
682*7c478bd9Sstevel@tonic-gate 				    args->arg.nd_hs->h_host,
683*7c478bd9Sstevel@tonic-gate 				    ndbuf4switch->result, ndbuf4switch->buffer,
684*7c478bd9Sstevel@tonic-gate 				    ndbuf4switch->buflen,
685*7c478bd9Sstevel@tonic-gate 				    args->arg.nss.host6.af_family,
686*7c478bd9Sstevel@tonic-gate 				    args->arg.nss.host6.flags, &h_errnop);
687*7c478bd9Sstevel@tonic-gate 				if (he == NULL) {
688*7c478bd9Sstevel@tonic-gate 					NSS_XbyY_FREE(&ndbuf4switch);
689*7c478bd9Sstevel@tonic-gate 					_nderror = h_errnop ?
690*7c478bd9Sstevel@tonic-gate 					    __herrno2netdir(h_errnop) :
691*7c478bd9Sstevel@tonic-gate 					    ND_NOHOST;
692*7c478bd9Sstevel@tonic-gate 					return (_nderror);
693*7c478bd9Sstevel@tonic-gate 				}
694*7c478bd9Sstevel@tonic-gate 				/*
695*7c478bd9Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
696*7c478bd9Sstevel@tonic-gate 				 * malloc's will be done,
697*7c478bd9Sstevel@tonic-gate 				 * freed using netdir_free.
698*7c478bd9Sstevel@tonic-gate 				 */
699*7c478bd9Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET6,
700*7c478bd9Sstevel@tonic-gate 		    ((struct hostent *)(ndbuf4switch->result))->h_addr_list,
701*7c478bd9Sstevel@tonic-gate 				    &server_port, res->nd_alist);
702*7c478bd9Sstevel@tonic-gate 				_nderror = ret;
703*7c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4switch);
704*7c478bd9Sstevel@tonic-gate 				return (ret);
705*7c478bd9Sstevel@tonic-gate 			} else {
706*7c478bd9Sstevel@tonic-gate 				int ret;
707*7c478bd9Sstevel@tonic-gate 				/*
708*7c478bd9Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
709*7c478bd9Sstevel@tonic-gate 				 * malloc's will be done,
710*7c478bd9Sstevel@tonic-gate 				 * freed using netdir_free.
711*7c478bd9Sstevel@tonic-gate 				 */
712*7c478bd9Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET6, haddrlist,
713*7c478bd9Sstevel@tonic-gate 					    &server_port, res->nd_alist);
714*7c478bd9Sstevel@tonic-gate 				FREE_return(ret)
715*7c478bd9Sstevel@tonic-gate 			}
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 		default:
718*7c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
719*7c478bd9Sstevel@tonic-gate 		return (ND_BADARG); /* should never happen */
720*7c478bd9Sstevel@tonic-gate 	}
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 	} else {
723*7c478bd9Sstevel@tonic-gate 		/* haddrlist is no longer used, so clean up */
724*7c478bd9Sstevel@tonic-gate 		if (inaddrs)
725*7c478bd9Sstevel@tonic-gate 			free(inaddrs);
726*7c478bd9Sstevel@tonic-gate 		if (baddrlist)
727*7c478bd9Sstevel@tonic-gate 			free(baddrlist);
728*7c478bd9Sstevel@tonic-gate 	}
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate 	/*
731*7c478bd9Sstevel@tonic-gate 	 * 3. We come this far only if nametoaddr libs are specified for
732*7c478bd9Sstevel@tonic-gate 	 *    inet transports and we are called by gethost/servbyname only.
733*7c478bd9Sstevel@tonic-gate 	 */
734*7c478bd9Sstevel@tonic-gate 	switch (args->op_t) {
735*7c478bd9Sstevel@tonic-gate 		struct	nd_hostserv service;
736*7c478bd9Sstevel@tonic-gate 		struct	nd_addrlist *addrs;
737*7c478bd9Sstevel@tonic-gate 		int ret;
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 		case NSS_HOST:
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 		service.h_host = (char *)args->arg.nss.host.name;
742*7c478bd9Sstevel@tonic-gate 		service.h_serv = NULL;
743*7c478bd9Sstevel@tonic-gate 		if ((_nderror = __classic_netdir_getbyname(nconf,
744*7c478bd9Sstevel@tonic-gate 			    &service, &addrs)) != ND_OK) {
745*7c478bd9Sstevel@tonic-gate 			*(res->nss.host.herrno_p) = nd2herrno(_nderror);
746*7c478bd9Sstevel@tonic-gate 			return (_nderror);
747*7c478bd9Sstevel@tonic-gate 		}
748*7c478bd9Sstevel@tonic-gate 		/*
749*7c478bd9Sstevel@tonic-gate 		 * convert addresses back into sockaddr for gethostbyname.
750*7c478bd9Sstevel@tonic-gate 		 */
751*7c478bd9Sstevel@tonic-gate 		ret = ndaddr2hent(AF_INET, service.h_host, addrs,
752*7c478bd9Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
753*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.buflen);
754*7c478bd9Sstevel@tonic-gate 		if (ret != ND_OK)
755*7c478bd9Sstevel@tonic-gate 			*(res->nss.host.herrno_p) = nd2herrno(ret);
756*7c478bd9Sstevel@tonic-gate 		netdir_free((char *)addrs, ND_ADDRLIST);
757*7c478bd9Sstevel@tonic-gate 		_nderror = ret;
758*7c478bd9Sstevel@tonic-gate 		return (ret);
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 		case NSS_SERV:
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 		if (args->arg.nss.serv.proto == NULL) {
763*7c478bd9Sstevel@tonic-gate 			/*
764*7c478bd9Sstevel@tonic-gate 			 * A similar HACK showed up in Solaris 2.3.
765*7c478bd9Sstevel@tonic-gate 			 * The caller wild-carded proto -- i.e. will
766*7c478bd9Sstevel@tonic-gate 			 * accept a match using tcp or udp for the port
767*7c478bd9Sstevel@tonic-gate 			 * number. Since we have no hope of getting
768*7c478bd9Sstevel@tonic-gate 			 * directly to a name service switch backend
769*7c478bd9Sstevel@tonic-gate 			 * from here that understands this semantics,
770*7c478bd9Sstevel@tonic-gate 			 * we try calling the netdir interfaces first
771*7c478bd9Sstevel@tonic-gate 			 * with "tcp" and then "udp".
772*7c478bd9Sstevel@tonic-gate 			 */
773*7c478bd9Sstevel@tonic-gate 			args->arg.nss.serv.proto = "tcp";
774*7c478bd9Sstevel@tonic-gate 			_nderror = _get_hostserv_inetnetdir_byname(nconf, args,
775*7c478bd9Sstevel@tonic-gate 			    res);
776*7c478bd9Sstevel@tonic-gate 			if (_nderror != ND_OK) {
777*7c478bd9Sstevel@tonic-gate 				args->arg.nss.serv.proto = "udp";
778*7c478bd9Sstevel@tonic-gate 				_nderror =
779*7c478bd9Sstevel@tonic-gate 				    _get_hostserv_inetnetdir_byname(nconf,
780*7c478bd9Sstevel@tonic-gate 				    args, res);
781*7c478bd9Sstevel@tonic-gate 			}
782*7c478bd9Sstevel@tonic-gate 			return (_nderror);
783*7c478bd9Sstevel@tonic-gate 		}
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 		/*
786*7c478bd9Sstevel@tonic-gate 		 * Third-parties should optimize their nametoaddr
787*7c478bd9Sstevel@tonic-gate 		 * libraries for the HOST_SELF case.
788*7c478bd9Sstevel@tonic-gate 		 */
789*7c478bd9Sstevel@tonic-gate 		service.h_host = HOST_SELF;
790*7c478bd9Sstevel@tonic-gate 		service.h_serv = (char *)args->arg.nss.serv.name;
791*7c478bd9Sstevel@tonic-gate 		if ((_nderror = __classic_netdir_getbyname(nconf,
792*7c478bd9Sstevel@tonic-gate 			    &service, &addrs)) != ND_OK) {
793*7c478bd9Sstevel@tonic-gate 			return (_nderror);
794*7c478bd9Sstevel@tonic-gate 		}
795*7c478bd9Sstevel@tonic-gate 		/*
796*7c478bd9Sstevel@tonic-gate 		 * convert addresses back into servent for getservbyname.
797*7c478bd9Sstevel@tonic-gate 		 */
798*7c478bd9Sstevel@tonic-gate 		_nderror = ndaddr2srent(service.h_serv,
799*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.proto,
800*7c478bd9Sstevel@tonic-gate 		    ((struct sockaddr_in *)addrs->n_addrs->buf)->sin_port,
801*7c478bd9Sstevel@tonic-gate 		    res->nss.serv,
802*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.buf, args->arg.nss.serv.buflen);
803*7c478bd9Sstevel@tonic-gate 		netdir_free((char *)addrs, ND_ADDRLIST);
804*7c478bd9Sstevel@tonic-gate 		return (_nderror);
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 		default:
807*7c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
808*7c478bd9Sstevel@tonic-gate 		return (ND_BADARG); /* should never happen */
809*7c478bd9Sstevel@tonic-gate 	}
810*7c478bd9Sstevel@tonic-gate }
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate /*
813*7c478bd9Sstevel@tonic-gate  * gethostbyaddr/servbyport always call this function; if they call
814*7c478bd9Sstevel@tonic-gate  * with nametoaddr libs in nconf, we call netdir_getbyaddr
815*7c478bd9Sstevel@tonic-gate  * implementation __classic_netdir_getbyaddr, otherwise nsswitch.
816*7c478bd9Sstevel@tonic-gate  *
817*7c478bd9Sstevel@tonic-gate  * netdir_getbyaddr calls this only if nametoaddr libs are NOT
818*7c478bd9Sstevel@tonic-gate  * specified for inet transports; i.e. it's supposed to follow
819*7c478bd9Sstevel@tonic-gate  * the name service switch.
820*7c478bd9Sstevel@tonic-gate  */
821*7c478bd9Sstevel@tonic-gate int
822*7c478bd9Sstevel@tonic-gate _get_hostserv_inetnetdir_byaddr(struct netconfig *nconf,
823*7c478bd9Sstevel@tonic-gate     struct nss_netdirbyaddr_in *args, union nss_netdirbyaddr_out *res)
824*7c478bd9Sstevel@tonic-gate {
825*7c478bd9Sstevel@tonic-gate 	if (nconf == 0) {
826*7c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
827*7c478bd9Sstevel@tonic-gate 		return (_nderror);
828*7c478bd9Sstevel@tonic-gate 	}
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate 	/*
831*7c478bd9Sstevel@tonic-gate 	 * 1. gethostbyaddr()/netdir_getbyaddr() special cases:
832*7c478bd9Sstevel@tonic-gate 	 */
833*7c478bd9Sstevel@tonic-gate 	switch (args->op_t) {
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 		case NSS_HOST:
836*7c478bd9Sstevel@tonic-gate 		/*
837*7c478bd9Sstevel@tonic-gate 		 * Worth the performance gain: assuming a lot of inet apps
838*7c478bd9Sstevel@tonic-gate 		 * actively use "127.0.0.1".
839*7c478bd9Sstevel@tonic-gate 		 */
840*7c478bd9Sstevel@tonic-gate 		if (*(uint32_t *)(args->arg.nss.host.addr) ==
841*7c478bd9Sstevel@tonic-gate 					htonl(INADDR_LOOPBACK)) {
842*7c478bd9Sstevel@tonic-gate 			mutex_lock(&nd_addr_lock);
843*7c478bd9Sstevel@tonic-gate 			IN_SET_LOOPBACK_ADDR(&sa_con);
844*7c478bd9Sstevel@tonic-gate 			_nderror = ndaddr2hent(AF_INET, LOCALHOST,
845*7c478bd9Sstevel@tonic-gate 			    &nd_conaddrlist, res->nss.host.hent,
846*7c478bd9Sstevel@tonic-gate 			    args->arg.nss.host.buf,
847*7c478bd9Sstevel@tonic-gate 			    args->arg.nss.host.buflen);
848*7c478bd9Sstevel@tonic-gate 			mutex_unlock(&nd_addr_lock);
849*7c478bd9Sstevel@tonic-gate 			if (_nderror != ND_OK)
850*7c478bd9Sstevel@tonic-gate 				*(res->nss.host.herrno_p) =
851*7c478bd9Sstevel@tonic-gate 				    nd2herrno(_nderror);
852*7c478bd9Sstevel@tonic-gate 			return (_nderror);
853*7c478bd9Sstevel@tonic-gate 		}
854*7c478bd9Sstevel@tonic-gate 		break;
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 		case NETDIR_BY:
857*7c478bd9Sstevel@tonic-gate 		case NETDIR_BY_NOSRV:
858*7c478bd9Sstevel@tonic-gate 		{
859*7c478bd9Sstevel@tonic-gate 			struct sockaddr_in *sin;
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 			if (args->arg.nd_nbuf == NULL) {
862*7c478bd9Sstevel@tonic-gate 				_nderror = ND_BADARG;
863*7c478bd9Sstevel@tonic-gate 				return (_nderror);
864*7c478bd9Sstevel@tonic-gate 			}
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 			/*
867*7c478bd9Sstevel@tonic-gate 			 * Validate the address which was passed
868*7c478bd9Sstevel@tonic-gate 			 * as the request.
869*7c478bd9Sstevel@tonic-gate 			 */
870*7c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)args->arg.nd_nbuf->buf;
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 			if ((args->arg.nd_nbuf->len !=
873*7c478bd9Sstevel@tonic-gate 				sizeof (struct sockaddr_in)) ||
874*7c478bd9Sstevel@tonic-gate 			    (sin->sin_family != AF_INET)) {
875*7c478bd9Sstevel@tonic-gate 				_nderror = ND_BADARG;
876*7c478bd9Sstevel@tonic-gate 				return (_nderror);
877*7c478bd9Sstevel@tonic-gate 			}
878*7c478bd9Sstevel@tonic-gate 		}
879*7c478bd9Sstevel@tonic-gate 		break;
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate 		case NETDIR_BY6:
882*7c478bd9Sstevel@tonic-gate 		case NETDIR_BY_NOSRV6:
883*7c478bd9Sstevel@tonic-gate 		{
884*7c478bd9Sstevel@tonic-gate 			struct sockaddr_in6 *sin6;
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 			if (args->arg.nd_nbuf == NULL) {
887*7c478bd9Sstevel@tonic-gate 				_nderror = ND_BADARG;
888*7c478bd9Sstevel@tonic-gate 				return (_nderror);
889*7c478bd9Sstevel@tonic-gate 			}
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate 			/*
892*7c478bd9Sstevel@tonic-gate 			 * Validate the address which was passed
893*7c478bd9Sstevel@tonic-gate 			 * as the request.
894*7c478bd9Sstevel@tonic-gate 			 */
895*7c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)args->arg.nd_nbuf->buf;
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 			if ((args->arg.nd_nbuf->len !=
898*7c478bd9Sstevel@tonic-gate 				sizeof (struct sockaddr_in6)) ||
899*7c478bd9Sstevel@tonic-gate 			    (sin6->sin6_family != AF_INET6)) {
900*7c478bd9Sstevel@tonic-gate 				_nderror = ND_BADARG;
901*7c478bd9Sstevel@tonic-gate 				return (_nderror);
902*7c478bd9Sstevel@tonic-gate 			}
903*7c478bd9Sstevel@tonic-gate 		}
904*7c478bd9Sstevel@tonic-gate 		break;
905*7c478bd9Sstevel@tonic-gate 
906*7c478bd9Sstevel@tonic-gate 	}
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 	/*
909*7c478bd9Sstevel@tonic-gate 	 * 2. Most common scenario. This is the way we ship /etc/netconfig.
910*7c478bd9Sstevel@tonic-gate 	 *    Emphasis on improving performance in the "if" part.
911*7c478bd9Sstevel@tonic-gate 	 */
912*7c478bd9Sstevel@tonic-gate 	if (nconf->nc_nlookups == 0) {
913*7c478bd9Sstevel@tonic-gate 		struct hostent	*he = NULL, *tmphe;
914*7c478bd9Sstevel@tonic-gate 		struct servent	*se = NULL;
915*7c478bd9Sstevel@tonic-gate 		nss_XbyY_buf_t	*ndbuf4host = 0;
916*7c478bd9Sstevel@tonic-gate 		nss_XbyY_buf_t	*ndbuf4serv = 0;
917*7c478bd9Sstevel@tonic-gate 		char	*proto =
918*7c478bd9Sstevel@tonic-gate 		    (strcmp(nconf->nc_proto, NC_TCP) == 0) ? NC_TCP : NC_UDP;
919*7c478bd9Sstevel@tonic-gate 		struct	sockaddr_in *sa;
920*7c478bd9Sstevel@tonic-gate 		struct sockaddr_in6 *sin6;
921*7c478bd9Sstevel@tonic-gate 		struct in_addr *addr4 = 0;
922*7c478bd9Sstevel@tonic-gate 		struct in6_addr v4mapbuf;
923*7c478bd9Sstevel@tonic-gate 		int	h_errnop;
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 	switch (args->op_t) {
926*7c478bd9Sstevel@tonic-gate 
927*7c478bd9Sstevel@tonic-gate 		case NSS_HOST:
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate 		he = DOOR_GETHOSTBYADDR_R(args->arg.nss.host.addr,
930*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.len, args->arg.nss.host.type,
931*7c478bd9Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
932*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.buflen,
933*7c478bd9Sstevel@tonic-gate 		    res->nss.host.herrno_p);
934*7c478bd9Sstevel@tonic-gate 		if (he == 0)
935*7c478bd9Sstevel@tonic-gate 			_nderror = ND_NOHOST;
936*7c478bd9Sstevel@tonic-gate 		else
937*7c478bd9Sstevel@tonic-gate 			_nderror = ND_OK;
938*7c478bd9Sstevel@tonic-gate 		return (_nderror);
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 		case NSS_HOST6:
942*7c478bd9Sstevel@tonic-gate 		he = DOOR_GETIPNODEBYADDR_R(args->arg.nss.host.addr,
943*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.len, args->arg.nss.host.type,
944*7c478bd9Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
945*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.buflen,
946*7c478bd9Sstevel@tonic-gate 		    res->nss.host.herrno_p);
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate 		if (he == 0)
949*7c478bd9Sstevel@tonic-gate 			return (ND_NOHOST);
950*7c478bd9Sstevel@tonic-gate 		return (ND_OK);
951*7c478bd9Sstevel@tonic-gate 
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 		case NSS_SERV:
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 		se = _switch_getservbyport_r(args->arg.nss.serv.port,
956*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.proto,
957*7c478bd9Sstevel@tonic-gate 		    res->nss.serv, args->arg.nss.serv.buf,
958*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.buflen);
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 		if (se == 0)
961*7c478bd9Sstevel@tonic-gate 			_nderror = ND_NOSERV;
962*7c478bd9Sstevel@tonic-gate 		else
963*7c478bd9Sstevel@tonic-gate 			_nderror = ND_OK;
964*7c478bd9Sstevel@tonic-gate 		return (_nderror);
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 		case NETDIR_BY:
967*7c478bd9Sstevel@tonic-gate 		case NETDIR_BY_NOSRV:
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 		GETSERVBUF(ndbuf4serv);
970*7c478bd9Sstevel@tonic-gate 		if (ndbuf4serv == 0) {
971*7c478bd9Sstevel@tonic-gate 			_nderror = ND_NOMEM;
972*7c478bd9Sstevel@tonic-gate 			return (_nderror);
973*7c478bd9Sstevel@tonic-gate 		}
974*7c478bd9Sstevel@tonic-gate 		sa = (struct sockaddr_in *)(args->arg.nd_nbuf->buf);
975*7c478bd9Sstevel@tonic-gate 		addr4 = (struct in_addr *)&(sa->sin_addr);
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 		/*
978*7c478bd9Sstevel@tonic-gate 		 * if NETDIR_BY_NOSRV or port == 0 skip the service
979*7c478bd9Sstevel@tonic-gate 		 * lookup.
980*7c478bd9Sstevel@tonic-gate 		 */
981*7c478bd9Sstevel@tonic-gate 		if (args->op_t != NETDIR_BY_NOSRV && sa->sin_port != 0) {
982*7c478bd9Sstevel@tonic-gate 			se = _switch_getservbyport_r(sa->sin_port, proto,
983*7c478bd9Sstevel@tonic-gate 			    ndbuf4serv->result, ndbuf4serv->buffer,
984*7c478bd9Sstevel@tonic-gate 				    ndbuf4serv->buflen);
985*7c478bd9Sstevel@tonic-gate 			if (!se) {
986*7c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4serv);
987*7c478bd9Sstevel@tonic-gate 				/*
988*7c478bd9Sstevel@tonic-gate 				 * We can live with this - i.e. the address
989*7c478bd9Sstevel@tonic-gate 				 * does not
990*7c478bd9Sstevel@tonic-gate 				 * belong to a well known service. The caller
991*7c478bd9Sstevel@tonic-gate 				 * traditionally accepts a stringified port
992*7c478bd9Sstevel@tonic-gate 				 * number
993*7c478bd9Sstevel@tonic-gate 				 * as the service name. The state of se is used
994*7c478bd9Sstevel@tonic-gate 				 * ahead to indicate the same.
995*7c478bd9Sstevel@tonic-gate 				 * However, we do not tolerate this nonsense
996*7c478bd9Sstevel@tonic-gate 				 * when we cannot get a host name. See below.
997*7c478bd9Sstevel@tonic-gate 				 */
998*7c478bd9Sstevel@tonic-gate 			}
999*7c478bd9Sstevel@tonic-gate 		}
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 		GETHOSTBUF(ndbuf4host);
1002*7c478bd9Sstevel@tonic-gate 		if (ndbuf4host == 0) {
1003*7c478bd9Sstevel@tonic-gate 			if (ndbuf4serv)
1004*7c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4serv);
1005*7c478bd9Sstevel@tonic-gate 			_nderror = ND_NOMEM;
1006*7c478bd9Sstevel@tonic-gate 			return (_nderror);
1007*7c478bd9Sstevel@tonic-gate 		}
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 		/*
1010*7c478bd9Sstevel@tonic-gate 		 * Since we're going to search the ipnodes (v6) path first,
1011*7c478bd9Sstevel@tonic-gate 		 * we need to treat the address as a v4mapped address.
1012*7c478bd9Sstevel@tonic-gate 		 */
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate 		IN6_INADDR_TO_V4MAPPED(addr4, &v4mapbuf);
1015*7c478bd9Sstevel@tonic-gate 		if ((tmphe = DOOR_GETIPNODEBYADDR_R((char *)&v4mapbuf,
1016*7c478bd9Sstevel@tonic-gate 		    16, AF_INET6, ndbuf4host->result,
1017*7c478bd9Sstevel@tonic-gate 			    ndbuf4host->buffer,
1018*7c478bd9Sstevel@tonic-gate 			    ndbuf4host->buflen, &h_errnop)) != NULL)
1019*7c478bd9Sstevel@tonic-gate 			he = __mappedtov4(tmphe, &h_errnop);
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 		if (!he) {
1022*7c478bd9Sstevel@tonic-gate 			/* Failover case, try hosts db for v4 address */
1023*7c478bd9Sstevel@tonic-gate 			he = DOOR_GETHOSTBYADDR_R((char *)
1024*7c478bd9Sstevel@tonic-gate 					&(sa->sin_addr.s_addr), 4,
1025*7c478bd9Sstevel@tonic-gate 					sa->sin_family, ndbuf4host->result,
1026*7c478bd9Sstevel@tonic-gate 					ndbuf4host->buffer, ndbuf4host->buflen,
1027*7c478bd9Sstevel@tonic-gate 					&h_errnop);
1028*7c478bd9Sstevel@tonic-gate 			if (!he) {
1029*7c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4host);
1030*7c478bd9Sstevel@tonic-gate 				if (ndbuf4serv)
1031*7c478bd9Sstevel@tonic-gate 					NSS_XbyY_FREE(&ndbuf4serv);
1032*7c478bd9Sstevel@tonic-gate 				_nderror = __herrno2netdir(h_errnop);
1033*7c478bd9Sstevel@tonic-gate 				return (_nderror);
1034*7c478bd9Sstevel@tonic-gate 			}
1035*7c478bd9Sstevel@tonic-gate 			/*
1036*7c478bd9Sstevel@tonic-gate 			 * Convert host names and service names into hostserv
1037*7c478bd9Sstevel@tonic-gate 			 * pairs. malloc's will be done, freed using
1038*7c478bd9Sstevel@tonic-gate 			 * netdir_free.
1039*7c478bd9Sstevel@tonic-gate 			 */
1040*7c478bd9Sstevel@tonic-gate 			h_errnop = hsents2ndhostservs(he, se,
1041*7c478bd9Sstevel@tonic-gate 			    sa->sin_port, res->nd_hslist);
1042*7c478bd9Sstevel@tonic-gate 		} else {
1043*7c478bd9Sstevel@tonic-gate 			/*
1044*7c478bd9Sstevel@tonic-gate 			 * Convert host names and service names into hostserv
1045*7c478bd9Sstevel@tonic-gate 			 * pairs. malloc's will be done, freed using
1046*7c478bd9Sstevel@tonic-gate 			 * netdir_free.
1047*7c478bd9Sstevel@tonic-gate 			 */
1048*7c478bd9Sstevel@tonic-gate 			h_errnop = hsents2ndhostservs(he, se,
1049*7c478bd9Sstevel@tonic-gate 			    sa->sin_port, res->nd_hslist);
1050*7c478bd9Sstevel@tonic-gate 			freehostent(he);
1051*7c478bd9Sstevel@tonic-gate 		}
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate 		NSS_XbyY_FREE(&ndbuf4host);
1054*7c478bd9Sstevel@tonic-gate 		if (ndbuf4serv)
1055*7c478bd9Sstevel@tonic-gate 		    NSS_XbyY_FREE(&ndbuf4serv);
1056*7c478bd9Sstevel@tonic-gate 		_nderror = __herrno2netdir(h_errnop);
1057*7c478bd9Sstevel@tonic-gate 		return (_nderror);
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate 		case NETDIR_BY6:
1060*7c478bd9Sstevel@tonic-gate 		case NETDIR_BY_NOSRV6:
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate 		GETSERVBUF(ndbuf4serv);
1063*7c478bd9Sstevel@tonic-gate 		if (ndbuf4serv == 0) {
1064*7c478bd9Sstevel@tonic-gate 			_nderror = ND_NOMEM;
1065*7c478bd9Sstevel@tonic-gate 			return (ND_NOMEM);
1066*7c478bd9Sstevel@tonic-gate 		}
1067*7c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)(args->arg.nd_nbuf->buf);
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 		/*
1070*7c478bd9Sstevel@tonic-gate 		 * if NETDIR_BY_NOSRV6 or port == 0 skip the service
1071*7c478bd9Sstevel@tonic-gate 		 * lookup.
1072*7c478bd9Sstevel@tonic-gate 		 */
1073*7c478bd9Sstevel@tonic-gate 		if (args->op_t != NETDIR_BY_NOSRV6 && sin6->sin6_port == 0) {
1074*7c478bd9Sstevel@tonic-gate 			se = _switch_getservbyport_r(sin6->sin6_port, proto,
1075*7c478bd9Sstevel@tonic-gate 			    ndbuf4serv->result, ndbuf4serv->buffer,
1076*7c478bd9Sstevel@tonic-gate 				    ndbuf4serv->buflen);
1077*7c478bd9Sstevel@tonic-gate 			if (!se) {
1078*7c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4serv);
1079*7c478bd9Sstevel@tonic-gate 				/*
1080*7c478bd9Sstevel@tonic-gate 				 * We can live with this - i.e. the address does
1081*7c478bd9Sstevel@tonic-gate 				 * not * belong to a well known service. The
1082*7c478bd9Sstevel@tonic-gate 				 * caller traditionally accepts a stringified
1083*7c478bd9Sstevel@tonic-gate 				 * port number
1084*7c478bd9Sstevel@tonic-gate 				 * as the service name. The state of se is used
1085*7c478bd9Sstevel@tonic-gate 				 * ahead to indicate the same.
1086*7c478bd9Sstevel@tonic-gate 				 * However, we do not tolerate this nonsense
1087*7c478bd9Sstevel@tonic-gate 				 * when we cannot get a host name. See below.
1088*7c478bd9Sstevel@tonic-gate 				 */
1089*7c478bd9Sstevel@tonic-gate 			}
1090*7c478bd9Sstevel@tonic-gate 		}
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 		GETHOSTBUF(ndbuf4host);
1093*7c478bd9Sstevel@tonic-gate 		if (ndbuf4host == 0) {
1094*7c478bd9Sstevel@tonic-gate 			if (ndbuf4serv)
1095*7c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4serv);
1096*7c478bd9Sstevel@tonic-gate 			_nderror = ND_NOMEM;
1097*7c478bd9Sstevel@tonic-gate 			return (_nderror);
1098*7c478bd9Sstevel@tonic-gate 		}
1099*7c478bd9Sstevel@tonic-gate 		he = DOOR_GETIPNODEBYADDR_R((char *)&(sin6->sin6_addr),
1100*7c478bd9Sstevel@tonic-gate 		    16, sin6->sin6_family, ndbuf4host->result,
1101*7c478bd9Sstevel@tonic-gate 			    ndbuf4host->buffer,
1102*7c478bd9Sstevel@tonic-gate 			    ndbuf4host->buflen, &h_errnop);
1103*7c478bd9Sstevel@tonic-gate 		if (!he) {
1104*7c478bd9Sstevel@tonic-gate 			NSS_XbyY_FREE(&ndbuf4host);
1105*7c478bd9Sstevel@tonic-gate 			if (ndbuf4serv)
1106*7c478bd9Sstevel@tonic-gate 			    NSS_XbyY_FREE(&ndbuf4serv);
1107*7c478bd9Sstevel@tonic-gate 			_nderror = __herrno2netdir(h_errnop);
1108*7c478bd9Sstevel@tonic-gate 			return (_nderror);
1109*7c478bd9Sstevel@tonic-gate 		}
1110*7c478bd9Sstevel@tonic-gate 		/*
1111*7c478bd9Sstevel@tonic-gate 		 * Convert host names and service names into hostserv
1112*7c478bd9Sstevel@tonic-gate 		 * pairs. malloc's will be done, freed using netdir_free.
1113*7c478bd9Sstevel@tonic-gate 		 */
1114*7c478bd9Sstevel@tonic-gate 		h_errnop = hsents2ndhostservs(he, se,
1115*7c478bd9Sstevel@tonic-gate 		    sin6->sin6_port, res->nd_hslist);
1116*7c478bd9Sstevel@tonic-gate 
1117*7c478bd9Sstevel@tonic-gate 		NSS_XbyY_FREE(&ndbuf4host);
1118*7c478bd9Sstevel@tonic-gate 		if (ndbuf4serv)
1119*7c478bd9Sstevel@tonic-gate 		    NSS_XbyY_FREE(&ndbuf4serv);
1120*7c478bd9Sstevel@tonic-gate 		_nderror = __herrno2netdir(h_errnop);
1121*7c478bd9Sstevel@tonic-gate 		return (_nderror);
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate 		default:
1124*7c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
1125*7c478bd9Sstevel@tonic-gate 		return (_nderror); /* should never happen */
1126*7c478bd9Sstevel@tonic-gate 	}
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate 	}
1129*7c478bd9Sstevel@tonic-gate 	/*
1130*7c478bd9Sstevel@tonic-gate 	 * 3. We come this far only if nametoaddr libs are specified for
1131*7c478bd9Sstevel@tonic-gate 	 *    inet transports and we are called by gethost/servbyname only.
1132*7c478bd9Sstevel@tonic-gate 	 */
1133*7c478bd9Sstevel@tonic-gate 	switch (args->op_t) {
1134*7c478bd9Sstevel@tonic-gate 		struct	netbuf nbuf;
1135*7c478bd9Sstevel@tonic-gate 		struct	nd_hostservlist *addrs;
1136*7c478bd9Sstevel@tonic-gate 		struct	sockaddr_in sa;
1137*7c478bd9Sstevel@tonic-gate 
1138*7c478bd9Sstevel@tonic-gate 		case NSS_HOST:
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate 		sa.sin_addr.s_addr = *(uint32_t *)args->arg.nss.host.addr;
1141*7c478bd9Sstevel@tonic-gate 		sa.sin_family = AF_INET;
1142*7c478bd9Sstevel@tonic-gate 		/* Hopefully, third-parties get this optimization */
1143*7c478bd9Sstevel@tonic-gate 		sa.sin_port = 0;
1144*7c478bd9Sstevel@tonic-gate 		nbuf.buf = (char *)&sa;
1145*7c478bd9Sstevel@tonic-gate 		nbuf.len = nbuf.maxlen = sizeof (sa);
1146*7c478bd9Sstevel@tonic-gate 		if ((_nderror = __classic_netdir_getbyaddr(nconf,
1147*7c478bd9Sstevel@tonic-gate 			    &addrs, &nbuf)) != 0) {
1148*7c478bd9Sstevel@tonic-gate 			*(res->nss.host.herrno_p) = nd2herrno(_nderror);
1149*7c478bd9Sstevel@tonic-gate 			return (_nderror);
1150*7c478bd9Sstevel@tonic-gate 		}
1151*7c478bd9Sstevel@tonic-gate 		/*
1152*7c478bd9Sstevel@tonic-gate 		 * convert the host-serv pairs into h_aliases and hent.
1153*7c478bd9Sstevel@tonic-gate 		 */
1154*7c478bd9Sstevel@tonic-gate 		_nderror = ndhostserv2hent(&nbuf, addrs, res->nss.host.hent,
1155*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.buf, args->arg.nss.host.buflen);
1156*7c478bd9Sstevel@tonic-gate 		if (_nderror != ND_OK)
1157*7c478bd9Sstevel@tonic-gate 			*(res->nss.host.herrno_p) = nd2herrno(_nderror);
1158*7c478bd9Sstevel@tonic-gate 		netdir_free((char *)addrs, ND_HOSTSERVLIST);
1159*7c478bd9Sstevel@tonic-gate 		return (_nderror);
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate 		case NSS_SERV:
1162*7c478bd9Sstevel@tonic-gate 
1163*7c478bd9Sstevel@tonic-gate 		if (args->arg.nss.serv.proto == NULL) {
1164*7c478bd9Sstevel@tonic-gate 			/*
1165*7c478bd9Sstevel@tonic-gate 			 * A similar HACK showed up in Solaris 2.3.
1166*7c478bd9Sstevel@tonic-gate 			 * The caller wild-carded proto -- i.e. will
1167*7c478bd9Sstevel@tonic-gate 			 * accept a match on tcp or udp for the port
1168*7c478bd9Sstevel@tonic-gate 			 * number. Since we have no hope of getting
1169*7c478bd9Sstevel@tonic-gate 			 * directly to a name service switch backend
1170*7c478bd9Sstevel@tonic-gate 			 * from here that understands this semantics,
1171*7c478bd9Sstevel@tonic-gate 			 * we try calling the netdir interfaces first
1172*7c478bd9Sstevel@tonic-gate 			 * with "tcp" and then "udp".
1173*7c478bd9Sstevel@tonic-gate 			 */
1174*7c478bd9Sstevel@tonic-gate 			args->arg.nss.serv.proto = "tcp";
1175*7c478bd9Sstevel@tonic-gate 			_nderror = _get_hostserv_inetnetdir_byaddr(nconf, args,
1176*7c478bd9Sstevel@tonic-gate 			    res);
1177*7c478bd9Sstevel@tonic-gate 			if (_nderror != ND_OK) {
1178*7c478bd9Sstevel@tonic-gate 				args->arg.nss.serv.proto = "udp";
1179*7c478bd9Sstevel@tonic-gate 				_nderror =
1180*7c478bd9Sstevel@tonic-gate 				    _get_hostserv_inetnetdir_byaddr(nconf,
1181*7c478bd9Sstevel@tonic-gate 					args, res);
1182*7c478bd9Sstevel@tonic-gate 			}
1183*7c478bd9Sstevel@tonic-gate 			return (_nderror);
1184*7c478bd9Sstevel@tonic-gate 		}
1185*7c478bd9Sstevel@tonic-gate 
1186*7c478bd9Sstevel@tonic-gate 		/*
1187*7c478bd9Sstevel@tonic-gate 		 * Third-party nametoaddr_libs should be optimized for
1188*7c478bd9Sstevel@tonic-gate 		 * this case. It also gives a special semantics twist to
1189*7c478bd9Sstevel@tonic-gate 		 * netdir_getbyaddr. Only for the INADDR_ANY case, it gives
1190*7c478bd9Sstevel@tonic-gate 		 * higher priority to service lookups (over host lookups).
1191*7c478bd9Sstevel@tonic-gate 		 * If service lookup fails, the backend returns ND_NOSERV to
1192*7c478bd9Sstevel@tonic-gate 		 * facilitate lookup in the "next" naming service.
1193*7c478bd9Sstevel@tonic-gate 		 * BugId: 1075403.
1194*7c478bd9Sstevel@tonic-gate 		 */
1195*7c478bd9Sstevel@tonic-gate 		sa.sin_addr.s_addr = INADDR_ANY;
1196*7c478bd9Sstevel@tonic-gate 		sa.sin_family = AF_INET;
1197*7c478bd9Sstevel@tonic-gate 		sa.sin_port = (ushort_t)args->arg.nss.serv.port;
1198*7c478bd9Sstevel@tonic-gate 		sa.sin_zero[0] = '\0';
1199*7c478bd9Sstevel@tonic-gate 		nbuf.buf = (char *)&sa;
1200*7c478bd9Sstevel@tonic-gate 		nbuf.len = nbuf.maxlen = sizeof (sa);
1201*7c478bd9Sstevel@tonic-gate 		if ((_nderror = __classic_netdir_getbyaddr(nconf,
1202*7c478bd9Sstevel@tonic-gate 			    &addrs, &nbuf)) != ND_OK) {
1203*7c478bd9Sstevel@tonic-gate 			return (_nderror);
1204*7c478bd9Sstevel@tonic-gate 		}
1205*7c478bd9Sstevel@tonic-gate 		/*
1206*7c478bd9Sstevel@tonic-gate 		 * convert the host-serv pairs into s_aliases and servent.
1207*7c478bd9Sstevel@tonic-gate 		 */
1208*7c478bd9Sstevel@tonic-gate 		_nderror = ndhostserv2srent(args->arg.nss.serv.port,
1209*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.proto, addrs, res->nss.serv,
1210*7c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.buf, args->arg.nss.serv.buflen);
1211*7c478bd9Sstevel@tonic-gate 		netdir_free((char *)addrs, ND_HOSTSERVLIST);
1212*7c478bd9Sstevel@tonic-gate 		return (_nderror);
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate 		default:
1215*7c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
1216*7c478bd9Sstevel@tonic-gate 		return (_nderror); /* should never happen */
1217*7c478bd9Sstevel@tonic-gate 	}
1218*7c478bd9Sstevel@tonic-gate }
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate /*
1221*7c478bd9Sstevel@tonic-gate  * Part II: Name Service Switch interfacing routines.
1222*7c478bd9Sstevel@tonic-gate  */
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_hosts);
1225*7c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_ipnodes);
1226*7c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_services);
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 
1229*7c478bd9Sstevel@tonic-gate /*
1230*7c478bd9Sstevel@tonic-gate  * There is a copy of __nss2herrno() in nsswitch/files/gethostent.c.
1231*7c478bd9Sstevel@tonic-gate  * It is there because /etc/lib/nss_files.so.1 cannot call
1232*7c478bd9Sstevel@tonic-gate  * routines in libnsl.  Care should be taken to keep the two copies
1233*7c478bd9Sstevel@tonic-gate  * in sync.
1234*7c478bd9Sstevel@tonic-gate  */
1235*7c478bd9Sstevel@tonic-gate int
1236*7c478bd9Sstevel@tonic-gate __nss2herrno(nss_status_t nsstat)
1237*7c478bd9Sstevel@tonic-gate {
1238*7c478bd9Sstevel@tonic-gate 	switch (nsstat) {
1239*7c478bd9Sstevel@tonic-gate 	case NSS_SUCCESS:
1240*7c478bd9Sstevel@tonic-gate 		/* no macro-defined success code for h_errno */
1241*7c478bd9Sstevel@tonic-gate 		return (0);
1242*7c478bd9Sstevel@tonic-gate 	case NSS_NOTFOUND:
1243*7c478bd9Sstevel@tonic-gate 		return (HOST_NOT_FOUND);
1244*7c478bd9Sstevel@tonic-gate 	case NSS_TRYAGAIN:
1245*7c478bd9Sstevel@tonic-gate 		return (TRY_AGAIN);
1246*7c478bd9Sstevel@tonic-gate 	case NSS_UNAVAIL:
1247*7c478bd9Sstevel@tonic-gate 		return (NO_RECOVERY);
1248*7c478bd9Sstevel@tonic-gate 	}
1249*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1250*7c478bd9Sstevel@tonic-gate 	return (0);	/* keep gcc happy */
1251*7c478bd9Sstevel@tonic-gate }
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate nss_status_t
1254*7c478bd9Sstevel@tonic-gate _herrno2nss(int h_errno)
1255*7c478bd9Sstevel@tonic-gate {
1256*7c478bd9Sstevel@tonic-gate 	switch (h_errno) {
1257*7c478bd9Sstevel@tonic-gate 	case 0:
1258*7c478bd9Sstevel@tonic-gate 		return (NSS_SUCCESS);
1259*7c478bd9Sstevel@tonic-gate 	case TRY_AGAIN:
1260*7c478bd9Sstevel@tonic-gate 		return (NSS_TRYAGAIN);
1261*7c478bd9Sstevel@tonic-gate 	case NO_RECOVERY:
1262*7c478bd9Sstevel@tonic-gate 	case NETDB_INTERNAL:
1263*7c478bd9Sstevel@tonic-gate 		return (NSS_UNAVAIL);
1264*7c478bd9Sstevel@tonic-gate 	case HOST_NOT_FOUND:
1265*7c478bd9Sstevel@tonic-gate 	case NO_DATA:
1266*7c478bd9Sstevel@tonic-gate 	default:
1267*7c478bd9Sstevel@tonic-gate 		return (NSS_NOTFOUND);
1268*7c478bd9Sstevel@tonic-gate 	}
1269*7c478bd9Sstevel@tonic-gate }
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate static int
1272*7c478bd9Sstevel@tonic-gate __herrno2netdir(int h_errnop)
1273*7c478bd9Sstevel@tonic-gate {
1274*7c478bd9Sstevel@tonic-gate 	switch (h_errnop) {
1275*7c478bd9Sstevel@tonic-gate 		case 0:
1276*7c478bd9Sstevel@tonic-gate 			return (ND_OK);
1277*7c478bd9Sstevel@tonic-gate 		case HOST_NOT_FOUND:
1278*7c478bd9Sstevel@tonic-gate 			return (ND_NOHOST);
1279*7c478bd9Sstevel@tonic-gate 		case TRY_AGAIN:
1280*7c478bd9Sstevel@tonic-gate 			return (ND_TRY_AGAIN);
1281*7c478bd9Sstevel@tonic-gate 		case NO_RECOVERY:
1282*7c478bd9Sstevel@tonic-gate 		case NETDB_INTERNAL:
1283*7c478bd9Sstevel@tonic-gate 			return (ND_NO_RECOVERY);
1284*7c478bd9Sstevel@tonic-gate 		case NO_DATA:
1285*7c478bd9Sstevel@tonic-gate 			return (ND_NO_DATA);
1286*7c478bd9Sstevel@tonic-gate 		default:
1287*7c478bd9Sstevel@tonic-gate 			return (ND_NOHOST);
1288*7c478bd9Sstevel@tonic-gate 	}
1289*7c478bd9Sstevel@tonic-gate }
1290*7c478bd9Sstevel@tonic-gate 
1291*7c478bd9Sstevel@tonic-gate /*
1292*7c478bd9Sstevel@tonic-gate  * The _switch_getXXbyYY_r() routines should be static.  They used to
1293*7c478bd9Sstevel@tonic-gate  * be exported in SunOS 5.3, and in fact publicised as work-around
1294*7c478bd9Sstevel@tonic-gate  * interfaces for getting CNAME/aliases, and therefore, we preserve
1295*7c478bd9Sstevel@tonic-gate  * their signatures here. Just in case.
1296*7c478bd9Sstevel@tonic-gate  */
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate struct hostent *
1299*7c478bd9Sstevel@tonic-gate _switch_gethostbyname_r(const char *name, struct hostent *result, char *buffer,
1300*7c478bd9Sstevel@tonic-gate     int buflen, int *h_errnop)
1301*7c478bd9Sstevel@tonic-gate {
1302*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1303*7c478bd9Sstevel@tonic-gate 	nss_status_t	res;
1304*7c478bd9Sstevel@tonic-gate 
1305*7c478bd9Sstevel@tonic-gate 	trace2(TR__switch_gethostbyname_r, 0, buflen);
1306*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent);
1307*7c478bd9Sstevel@tonic-gate 	arg.key.name	= name;
1308*7c478bd9Sstevel@tonic-gate 	arg.stayopen	= 0;
1309*7c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root_hosts, _nss_initf_hosts,
1310*7c478bd9Sstevel@tonic-gate 	    NSS_DBOP_HOSTS_BYNAME, &arg);
1311*7c478bd9Sstevel@tonic-gate 	arg.status = res;
1312*7c478bd9Sstevel@tonic-gate 	*h_errnop = arg.h_errno;
1313*7c478bd9Sstevel@tonic-gate 	if (arg.returnval != NULL)
1314*7c478bd9Sstevel@tonic-gate 		order_haddrlist_af(result->h_addrtype, result->h_addr_list);
1315*7c478bd9Sstevel@tonic-gate 	trace2(TR__switch_gethostbyname_r, 1, buflen);
1316*7c478bd9Sstevel@tonic-gate 	return ((struct hostent *)NSS_XbyY_FINI(&arg));
1317*7c478bd9Sstevel@tonic-gate }
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate struct hostent *
1320*7c478bd9Sstevel@tonic-gate _switch_getipnodebyname_r(const char *name, struct hostent *result,
1321*7c478bd9Sstevel@tonic-gate     char *buffer, int buflen, int af_family, int flags, int *h_errnop)
1322*7c478bd9Sstevel@tonic-gate {
1323*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1324*7c478bd9Sstevel@tonic-gate 	nss_status_t	res;
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate 	trace2(TR__switch_getipnodebyname_r, 0, buflen);
1327*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6);
1328*7c478bd9Sstevel@tonic-gate 	arg.key.ipnode.name	= name;
1329*7c478bd9Sstevel@tonic-gate 	arg.key.ipnode.af_family = af_family;
1330*7c478bd9Sstevel@tonic-gate 	arg.key.ipnode.flags = flags;
1331*7c478bd9Sstevel@tonic-gate 	arg.stayopen	= 0;
1332*7c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes,
1333*7c478bd9Sstevel@tonic-gate 	    NSS_DBOP_IPNODES_BYNAME, &arg);
1334*7c478bd9Sstevel@tonic-gate 	arg.status = res;
1335*7c478bd9Sstevel@tonic-gate 	*h_errnop = arg.h_errno;
1336*7c478bd9Sstevel@tonic-gate 	if (arg.returnval != NULL)
1337*7c478bd9Sstevel@tonic-gate 		order_haddrlist_af(result->h_addrtype, result->h_addr_list);
1338*7c478bd9Sstevel@tonic-gate 	trace2(TR__switch_getipnodebyname_r, 1, buflen);
1339*7c478bd9Sstevel@tonic-gate 	return ((struct hostent *)NSS_XbyY_FINI(&arg));
1340*7c478bd9Sstevel@tonic-gate }
1341*7c478bd9Sstevel@tonic-gate 
1342*7c478bd9Sstevel@tonic-gate struct hostent *
1343*7c478bd9Sstevel@tonic-gate _switch_gethostbyaddr_r(const char *addr, int len, int type,
1344*7c478bd9Sstevel@tonic-gate     struct hostent *result, char *buffer, int buflen, int *h_errnop)
1345*7c478bd9Sstevel@tonic-gate {
1346*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1347*7c478bd9Sstevel@tonic-gate 	nss_status_t	res;
1348*7c478bd9Sstevel@tonic-gate 
1349*7c478bd9Sstevel@tonic-gate 	trace3(TR__switch_gethostbyaddr_r, 0, len, buflen);
1350*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent);
1351*7c478bd9Sstevel@tonic-gate 	arg.key.hostaddr.addr	= addr;
1352*7c478bd9Sstevel@tonic-gate 	arg.key.hostaddr.len	= len;
1353*7c478bd9Sstevel@tonic-gate 	arg.key.hostaddr.type	= type;
1354*7c478bd9Sstevel@tonic-gate 	arg.stayopen		= 0;
1355*7c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root_hosts, _nss_initf_hosts,
1356*7c478bd9Sstevel@tonic-gate 	    NSS_DBOP_HOSTS_BYADDR, &arg);
1357*7c478bd9Sstevel@tonic-gate 	arg.status = res;
1358*7c478bd9Sstevel@tonic-gate 	*h_errnop = arg.h_errno;
1359*7c478bd9Sstevel@tonic-gate 	trace3(TR__switch_gethostbyaddr_r, 1, len, buflen);
1360*7c478bd9Sstevel@tonic-gate 	return (struct hostent *)NSS_XbyY_FINI(&arg);
1361*7c478bd9Sstevel@tonic-gate }
1362*7c478bd9Sstevel@tonic-gate 
1363*7c478bd9Sstevel@tonic-gate struct hostent *
1364*7c478bd9Sstevel@tonic-gate _switch_getipnodebyaddr_r(const char *addr, int len, int type,
1365*7c478bd9Sstevel@tonic-gate     struct hostent *result, char *buffer, int buflen, int *h_errnop)
1366*7c478bd9Sstevel@tonic-gate {
1367*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1368*7c478bd9Sstevel@tonic-gate 	nss_status_t	res;
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 	trace3(TR__switch_getipnodebyaddr_r, 0, len, buflen);
1371*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6);
1372*7c478bd9Sstevel@tonic-gate 	arg.key.hostaddr.addr	= addr;
1373*7c478bd9Sstevel@tonic-gate 	arg.key.hostaddr.len	= len;
1374*7c478bd9Sstevel@tonic-gate 	arg.key.hostaddr.type	= type;
1375*7c478bd9Sstevel@tonic-gate 	arg.stayopen		= 0;
1376*7c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes,
1377*7c478bd9Sstevel@tonic-gate 	    NSS_DBOP_IPNODES_BYADDR, &arg);
1378*7c478bd9Sstevel@tonic-gate 	arg.status = res;
1379*7c478bd9Sstevel@tonic-gate 	*h_errnop = arg.h_errno;
1380*7c478bd9Sstevel@tonic-gate 	trace3(TR__switch_getipnodebyaddr_r, 1, len, buflen);
1381*7c478bd9Sstevel@tonic-gate 	return (struct hostent *)NSS_XbyY_FINI(&arg);
1382*7c478bd9Sstevel@tonic-gate }
1383*7c478bd9Sstevel@tonic-gate 
1384*7c478bd9Sstevel@tonic-gate static void
1385*7c478bd9Sstevel@tonic-gate _nss_initf_services(nss_db_params_t *p)
1386*7c478bd9Sstevel@tonic-gate {
1387*7c478bd9Sstevel@tonic-gate 	/* === need tracepoints */
1388*7c478bd9Sstevel@tonic-gate 	p->name	= NSS_DBNAM_SERVICES;
1389*7c478bd9Sstevel@tonic-gate 	p->default_config = NSS_DEFCONF_SERVICES;
1390*7c478bd9Sstevel@tonic-gate }
1391*7c478bd9Sstevel@tonic-gate 
1392*7c478bd9Sstevel@tonic-gate struct servent *
1393*7c478bd9Sstevel@tonic-gate _switch_getservbyname_r(const char *name, const char *proto,
1394*7c478bd9Sstevel@tonic-gate     struct servent *result, char *buffer, int buflen)
1395*7c478bd9Sstevel@tonic-gate {
1396*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1397*7c478bd9Sstevel@tonic-gate 	nss_status_t	res;
1398*7c478bd9Sstevel@tonic-gate 
1399*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent);
1400*7c478bd9Sstevel@tonic-gate 	arg.key.serv.serv.name	= name;
1401*7c478bd9Sstevel@tonic-gate 	arg.key.serv.proto	= proto;
1402*7c478bd9Sstevel@tonic-gate 	arg.stayopen		= 0;
1403*7c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root_services, _nss_initf_services,
1404*7c478bd9Sstevel@tonic-gate 	    NSS_DBOP_SERVICES_BYNAME, &arg);
1405*7c478bd9Sstevel@tonic-gate 	arg.status = res;
1406*7c478bd9Sstevel@tonic-gate 	return ((struct servent *)NSS_XbyY_FINI(&arg));
1407*7c478bd9Sstevel@tonic-gate }
1408*7c478bd9Sstevel@tonic-gate 
1409*7c478bd9Sstevel@tonic-gate struct servent *
1410*7c478bd9Sstevel@tonic-gate _switch_getservbyport_r(int port, const char *proto, struct servent *result,
1411*7c478bd9Sstevel@tonic-gate     char *buffer, int buflen)
1412*7c478bd9Sstevel@tonic-gate {
1413*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1414*7c478bd9Sstevel@tonic-gate 	nss_status_t	res;
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent);
1417*7c478bd9Sstevel@tonic-gate 	arg.key.serv.serv.port	= port;
1418*7c478bd9Sstevel@tonic-gate 	arg.key.serv.proto	= proto;
1419*7c478bd9Sstevel@tonic-gate 	arg.stayopen		= 0;
1420*7c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root_services, _nss_initf_services,
1421*7c478bd9Sstevel@tonic-gate 	    NSS_DBOP_SERVICES_BYPORT, &arg);
1422*7c478bd9Sstevel@tonic-gate 	arg.status = res;
1423*7c478bd9Sstevel@tonic-gate 	return ((struct servent *)NSS_XbyY_FINI(&arg));
1424*7c478bd9Sstevel@tonic-gate }
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate 
1427*7c478bd9Sstevel@tonic-gate /*
1428*7c478bd9Sstevel@tonic-gate  * Return values: 0 = success, 1 = parse error, 2 = erange ...
1429*7c478bd9Sstevel@tonic-gate  * The structure pointer passed in is a structure in the caller's space
1430*7c478bd9Sstevel@tonic-gate  * wherein the field pointers would be set to areas in the buffer if
1431*7c478bd9Sstevel@tonic-gate  * need be. instring and buffer should be separate areas.
1432*7c478bd9Sstevel@tonic-gate  *
1433*7c478bd9Sstevel@tonic-gate  * Defined here because we need it and we (libnsl) cannot have a dependency
1434*7c478bd9Sstevel@tonic-gate  * on libsocket (however, libsocket always depends on libnsl).
1435*7c478bd9Sstevel@tonic-gate  */
1436*7c478bd9Sstevel@tonic-gate int
1437*7c478bd9Sstevel@tonic-gate str2servent(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
1438*7c478bd9Sstevel@tonic-gate {
1439*7c478bd9Sstevel@tonic-gate 	struct servent	*serv	= (struct servent *)ent;
1440*7c478bd9Sstevel@tonic-gate 	const char	*p, *fieldstart, *limit, *namestart;
1441*7c478bd9Sstevel@tonic-gate 	ssize_t		fieldlen, namelen = 0;
1442*7c478bd9Sstevel@tonic-gate 	char		numbuf[12];
1443*7c478bd9Sstevel@tonic-gate 	char		*numend;
1444*7c478bd9Sstevel@tonic-gate 
1445*7c478bd9Sstevel@tonic-gate 	if ((instr >= buffer && (buffer + buflen) > instr) ||
1446*7c478bd9Sstevel@tonic-gate 	    (buffer >= instr && (instr + lenstr) > buffer)) {
1447*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
1448*7c478bd9Sstevel@tonic-gate 	}
1449*7c478bd9Sstevel@tonic-gate 
1450*7c478bd9Sstevel@tonic-gate 	p = instr;
1451*7c478bd9Sstevel@tonic-gate 	limit = p + lenstr;
1452*7c478bd9Sstevel@tonic-gate 
1453*7c478bd9Sstevel@tonic-gate 	while (p < limit && isspace(*p)) {
1454*7c478bd9Sstevel@tonic-gate 		p++;
1455*7c478bd9Sstevel@tonic-gate 	}
1456*7c478bd9Sstevel@tonic-gate 	namestart = p;
1457*7c478bd9Sstevel@tonic-gate 	while (p < limit && !isspace(*p)) {
1458*7c478bd9Sstevel@tonic-gate 		p++;		/* Skip over the canonical name */
1459*7c478bd9Sstevel@tonic-gate 	}
1460*7c478bd9Sstevel@tonic-gate 	namelen = p - namestart;
1461*7c478bd9Sstevel@tonic-gate 
1462*7c478bd9Sstevel@tonic-gate 	if (buflen <= namelen) { /* not enough buffer */
1463*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
1464*7c478bd9Sstevel@tonic-gate 	}
1465*7c478bd9Sstevel@tonic-gate 	(void) memcpy(buffer, namestart, namelen);
1466*7c478bd9Sstevel@tonic-gate 	buffer[namelen] = '\0';
1467*7c478bd9Sstevel@tonic-gate 	serv->s_name = buffer;
1468*7c478bd9Sstevel@tonic-gate 
1469*7c478bd9Sstevel@tonic-gate 	while (p < limit && isspace(*p)) {
1470*7c478bd9Sstevel@tonic-gate 		p++;
1471*7c478bd9Sstevel@tonic-gate 	}
1472*7c478bd9Sstevel@tonic-gate 
1473*7c478bd9Sstevel@tonic-gate 	fieldstart = p;
1474*7c478bd9Sstevel@tonic-gate 	do {
1475*7c478bd9Sstevel@tonic-gate 		if (p > limit || isspace(*p)) {
1476*7c478bd9Sstevel@tonic-gate 			/* Syntax error -- no port/proto */
1477*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
1478*7c478bd9Sstevel@tonic-gate 		}
1479*7c478bd9Sstevel@tonic-gate 	}
1480*7c478bd9Sstevel@tonic-gate 	while (*p++ != '/');
1481*7c478bd9Sstevel@tonic-gate 	fieldlen = p - fieldstart - 1;
1482*7c478bd9Sstevel@tonic-gate 	if (fieldlen == 0 || fieldlen >= sizeof (numbuf)) {
1483*7c478bd9Sstevel@tonic-gate 		/* Syntax error -- supposed number is empty or too long */
1484*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
1485*7c478bd9Sstevel@tonic-gate 	}
1486*7c478bd9Sstevel@tonic-gate 	(void) memcpy(numbuf, fieldstart, fieldlen);
1487*7c478bd9Sstevel@tonic-gate 	numbuf[fieldlen] = '\0';
1488*7c478bd9Sstevel@tonic-gate 	serv->s_port = htons((int)strtol(numbuf, &numend, 10));
1489*7c478bd9Sstevel@tonic-gate 	if (*numend != '\0') {
1490*7c478bd9Sstevel@tonic-gate 		/* Syntax error -- port number isn't a number */
1491*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
1492*7c478bd9Sstevel@tonic-gate 	}
1493*7c478bd9Sstevel@tonic-gate 
1494*7c478bd9Sstevel@tonic-gate 	fieldstart = p;
1495*7c478bd9Sstevel@tonic-gate 	while (p < limit && !isspace(*p)) {
1496*7c478bd9Sstevel@tonic-gate 		p++;		/* Scan the protocol name */
1497*7c478bd9Sstevel@tonic-gate 	}
1498*7c478bd9Sstevel@tonic-gate 	fieldlen = p - fieldstart + 1;		/* Include '\0' this time */
1499*7c478bd9Sstevel@tonic-gate 	if (fieldlen > buflen - namelen - 1) {
1500*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
1501*7c478bd9Sstevel@tonic-gate 	}
1502*7c478bd9Sstevel@tonic-gate 	serv->s_proto = buffer + namelen + 1;
1503*7c478bd9Sstevel@tonic-gate 	(void) memcpy(serv->s_proto, fieldstart, fieldlen - 1);
1504*7c478bd9Sstevel@tonic-gate 	serv->s_proto[fieldlen - 1] = '\0';
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate 	while (p < limit && isspace(*p)) {
1507*7c478bd9Sstevel@tonic-gate 		p++;
1508*7c478bd9Sstevel@tonic-gate 	}
1509*7c478bd9Sstevel@tonic-gate 	/*
1510*7c478bd9Sstevel@tonic-gate 	 * Although nss_files_XY_all calls us with # stripped,
1511*7c478bd9Sstevel@tonic-gate 	 * we should be able to deal with it here in order to
1512*7c478bd9Sstevel@tonic-gate 	 * be more useful.
1513*7c478bd9Sstevel@tonic-gate 	 */
1514*7c478bd9Sstevel@tonic-gate 	if (p >= limit || *p == '#') { /* no aliases, no problem */
1515*7c478bd9Sstevel@tonic-gate 		char **ptr;
1516*7c478bd9Sstevel@tonic-gate 
1517*7c478bd9Sstevel@tonic-gate 		ptr = (char **)ROUND_UP(buffer + namelen + 1 + fieldlen,
1518*7c478bd9Sstevel@tonic-gate 		    sizeof (char *));
1519*7c478bd9Sstevel@tonic-gate 		if ((char *)ptr >= buffer + buflen) {
1520*7c478bd9Sstevel@tonic-gate 			/* hope they don't try to peek in */
1521*7c478bd9Sstevel@tonic-gate 			serv->s_aliases = 0;
1522*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_ERANGE);
1523*7c478bd9Sstevel@tonic-gate 		} else {
1524*7c478bd9Sstevel@tonic-gate 			*ptr = 0;
1525*7c478bd9Sstevel@tonic-gate 			serv->s_aliases = ptr;
1526*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
1527*7c478bd9Sstevel@tonic-gate 		}
1528*7c478bd9Sstevel@tonic-gate 	}
1529*7c478bd9Sstevel@tonic-gate 	serv->s_aliases = _nss_netdb_aliases(p, (int)(lenstr - (p - instr)),
1530*7c478bd9Sstevel@tonic-gate 	    buffer + namelen + 1 + fieldlen,
1531*7c478bd9Sstevel@tonic-gate 	    (int)(buflen - namelen - 1 - fieldlen));
1532*7c478bd9Sstevel@tonic-gate 	return (NSS_STR_PARSE_SUCCESS);
1533*7c478bd9Sstevel@tonic-gate }
1534*7c478bd9Sstevel@tonic-gate 
1535*7c478bd9Sstevel@tonic-gate /*
1536*7c478bd9Sstevel@tonic-gate  * Part III: All `n sundry routines that are useful only in this
1537*7c478bd9Sstevel@tonic-gate  * module. In the interest of keeping this source file shorter,
1538*7c478bd9Sstevel@tonic-gate  * we would create them a new module only if the linker allowed
1539*7c478bd9Sstevel@tonic-gate  * "library-static" functions.
1540*7c478bd9Sstevel@tonic-gate  *
1541*7c478bd9Sstevel@tonic-gate  * Routines to order addresses based on local interfaces and netmasks,
1542*7c478bd9Sstevel@tonic-gate  * to get and check reserved ports, and to get broadcast nets.
1543*7c478bd9Sstevel@tonic-gate  */
1544*7c478bd9Sstevel@tonic-gate 
1545*7c478bd9Sstevel@tonic-gate union __v4v6addr {
1546*7c478bd9Sstevel@tonic-gate 	struct in6_addr	in6;
1547*7c478bd9Sstevel@tonic-gate 	struct in_addr	in4;
1548*7c478bd9Sstevel@tonic-gate };
1549*7c478bd9Sstevel@tonic-gate 
1550*7c478bd9Sstevel@tonic-gate struct __ifaddr {
1551*7c478bd9Sstevel@tonic-gate 	sa_family_t		af;
1552*7c478bd9Sstevel@tonic-gate 	union __v4v6addr	addr;
1553*7c478bd9Sstevel@tonic-gate 	union __v4v6addr	mask;
1554*7c478bd9Sstevel@tonic-gate };
1555*7c478bd9Sstevel@tonic-gate 
1556*7c478bd9Sstevel@tonic-gate struct ifinfo {
1557*7c478bd9Sstevel@tonic-gate 	int		count;
1558*7c478bd9Sstevel@tonic-gate 	struct __ifaddr	*addresses;
1559*7c478bd9Sstevel@tonic-gate };
1560*7c478bd9Sstevel@tonic-gate 
1561*7c478bd9Sstevel@tonic-gate typedef enum {ADDR_ONLINK = 0, ADDR_OFFLINK} addr_class_t;
1562*7c478bd9Sstevel@tonic-gate #define	ADDR_NUMCLASSES	2
1563*7c478bd9Sstevel@tonic-gate 
1564*7c478bd9Sstevel@tonic-gate typedef enum {IF_ADDR, IF_MASK}	__ifaddr_type;
1565*7c478bd9Sstevel@tonic-gate static int	__inet_ifassign(sa_family_t, struct __ifaddr *, __ifaddr_type,
1566*7c478bd9Sstevel@tonic-gate 				void *);
1567*7c478bd9Sstevel@tonic-gate int		__inet_address_is_local_af(void *, sa_family_t, void *);
1568*7c478bd9Sstevel@tonic-gate 
1569*7c478bd9Sstevel@tonic-gate #define	ifaf(index)	(localinfo->addresses[index].af)
1570*7c478bd9Sstevel@tonic-gate #define	ifaddr4(index)	(localinfo->addresses[index].addr.in4)
1571*7c478bd9Sstevel@tonic-gate #define	ifaddr6(index)	(localinfo->addresses[index].addr.in6)
1572*7c478bd9Sstevel@tonic-gate #define	ifmask4(index)	(localinfo->addresses[index].mask.in4)
1573*7c478bd9Sstevel@tonic-gate #define	ifmask6(index)	(localinfo->addresses[index].mask.in6)
1574*7c478bd9Sstevel@tonic-gate #define	ifinfosize(n)	(sizeof (struct ifinfo) + (n)*sizeof (struct __ifaddr))
1575*7c478bd9Sstevel@tonic-gate 
1576*7c478bd9Sstevel@tonic-gate #define	lifraddrp(lifr)	((lifr.lifr_addr.ss_family == AF_INET6) ? \
1577*7c478bd9Sstevel@tonic-gate 	(void *)&((struct sockaddr_in6 *)&lifr.lifr_addr)->sin6_addr : \
1578*7c478bd9Sstevel@tonic-gate 	(void *)&((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr)
1579*7c478bd9Sstevel@tonic-gate 
1580*7c478bd9Sstevel@tonic-gate #define	ifassign(lifr, index, type) \
1581*7c478bd9Sstevel@tonic-gate 			__inet_ifassign(lifr.lifr_addr.ss_family, \
1582*7c478bd9Sstevel@tonic-gate 				&localinfo->addresses[index], type, \
1583*7c478bd9Sstevel@tonic-gate 				lifraddrp(lifr))
1584*7c478bd9Sstevel@tonic-gate 
1585*7c478bd9Sstevel@tonic-gate /*
1586*7c478bd9Sstevel@tonic-gate  * The number of nanoseconds the order_haddrlist_inet() function waits
1587*7c478bd9Sstevel@tonic-gate  * to retreive IP interface information.  The default is five minutes.
1588*7c478bd9Sstevel@tonic-gate  */
1589*7c478bd9Sstevel@tonic-gate #define	IFINFOTIMEOUT	((hrtime_t)300 * NANOSEC)
1590*7c478bd9Sstevel@tonic-gate 
1591*7c478bd9Sstevel@tonic-gate /*
1592*7c478bd9Sstevel@tonic-gate  * Sort the addresses in haddrlist.  Since the sorting algorithms are
1593*7c478bd9Sstevel@tonic-gate  * address-family specific, the work is done in the address-family
1594*7c478bd9Sstevel@tonic-gate  * specific order_haddrlist_<family> functions.
1595*7c478bd9Sstevel@tonic-gate  *
1596*7c478bd9Sstevel@tonic-gate  * Do not sort addresses if SORT_ADDRS variable is set to NO or FALSE
1597*7c478bd9Sstevel@tonic-gate  * in the configuration file /etc/default/nss. This is useful in case
1598*7c478bd9Sstevel@tonic-gate  * the order of addresses returned by the nameserver needs to be
1599*7c478bd9Sstevel@tonic-gate  * maintained. (DNS round robin feature is one example)
1600*7c478bd9Sstevel@tonic-gate  */
1601*7c478bd9Sstevel@tonic-gate void
1602*7c478bd9Sstevel@tonic-gate order_haddrlist_af(sa_family_t af, char **haddrlist)
1603*7c478bd9Sstevel@tonic-gate {
1604*7c478bd9Sstevel@tonic-gate 	size_t			addrcount;
1605*7c478bd9Sstevel@tonic-gate 	char			**addrptr;
1606*7c478bd9Sstevel@tonic-gate 	static boolean_t	checksortcfg = B_TRUE;
1607*7c478bd9Sstevel@tonic-gate 	static boolean_t	nosort = B_FALSE;
1608*7c478bd9Sstevel@tonic-gate 	static mutex_t		checksortcfg_lock = DEFAULTMUTEX;
1609*7c478bd9Sstevel@tonic-gate 
1610*7c478bd9Sstevel@tonic-gate 	if (haddrlist == NULL)
1611*7c478bd9Sstevel@tonic-gate 		return;
1612*7c478bd9Sstevel@tonic-gate 
1613*7c478bd9Sstevel@tonic-gate 	/*
1614*7c478bd9Sstevel@tonic-gate 	 * Check if SORT_ADDRS is set to NO or FALSE in the configuration
1615*7c478bd9Sstevel@tonic-gate 	 * file.  We do not have to sort addresses in that case.
1616*7c478bd9Sstevel@tonic-gate 	 */
1617*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&checksortcfg_lock);
1618*7c478bd9Sstevel@tonic-gate 	if (checksortcfg == B_TRUE) {
1619*7c478bd9Sstevel@tonic-gate 		checksortcfg = B_FALSE;
1620*7c478bd9Sstevel@tonic-gate 		nosort = _read_nsw_file();
1621*7c478bd9Sstevel@tonic-gate 	}
1622*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&checksortcfg_lock);
1623*7c478bd9Sstevel@tonic-gate 
1624*7c478bd9Sstevel@tonic-gate 	if (nosort)
1625*7c478bd9Sstevel@tonic-gate 		return;
1626*7c478bd9Sstevel@tonic-gate 
1627*7c478bd9Sstevel@tonic-gate 	/* Count the addresses to sort */
1628*7c478bd9Sstevel@tonic-gate 	addrcount = 0;
1629*7c478bd9Sstevel@tonic-gate 	for (addrptr = haddrlist; *addrptr != NULL; addrptr++)
1630*7c478bd9Sstevel@tonic-gate 		addrcount++;
1631*7c478bd9Sstevel@tonic-gate 
1632*7c478bd9Sstevel@tonic-gate 	/*
1633*7c478bd9Sstevel@tonic-gate 	 * If there's only one address or no addresses to sort, then
1634*7c478bd9Sstevel@tonic-gate 	 * there's nothing for us to do.
1635*7c478bd9Sstevel@tonic-gate 	 */
1636*7c478bd9Sstevel@tonic-gate 	if (addrcount <= 1)
1637*7c478bd9Sstevel@tonic-gate 		return;
1638*7c478bd9Sstevel@tonic-gate 
1639*7c478bd9Sstevel@tonic-gate 	/* Call the address-family specific sorting functions. */
1640*7c478bd9Sstevel@tonic-gate 	switch (af) {
1641*7c478bd9Sstevel@tonic-gate 	case AF_INET:
1642*7c478bd9Sstevel@tonic-gate 		order_haddrlist_inet(haddrlist, addrcount);
1643*7c478bd9Sstevel@tonic-gate 		break;
1644*7c478bd9Sstevel@tonic-gate 	case AF_INET6:
1645*7c478bd9Sstevel@tonic-gate 		order_haddrlist_inet6(haddrlist, addrcount);
1646*7c478bd9Sstevel@tonic-gate 		break;
1647*7c478bd9Sstevel@tonic-gate 	default:
1648*7c478bd9Sstevel@tonic-gate 		break;
1649*7c478bd9Sstevel@tonic-gate 	}
1650*7c478bd9Sstevel@tonic-gate }
1651*7c478bd9Sstevel@tonic-gate 
1652*7c478bd9Sstevel@tonic-gate /*
1653*7c478bd9Sstevel@tonic-gate  * Move any local (on-link) addresses toward the beginning of haddrlist.
1654*7c478bd9Sstevel@tonic-gate  * The order within these two classes is preserved.
1655*7c478bd9Sstevel@tonic-gate  *
1656*7c478bd9Sstevel@tonic-gate  * The interface list is retrieved no more often than every
1657*7c478bd9Sstevel@tonic-gate  * IFINFOTIMEOUT nanoseconds. Access to the interface list is
1658*7c478bd9Sstevel@tonic-gate  * protected by an RW lock.
1659*7c478bd9Sstevel@tonic-gate  *
1660*7c478bd9Sstevel@tonic-gate  * If this function encounters an error, haddrlist is unaltered.
1661*7c478bd9Sstevel@tonic-gate  */
1662*7c478bd9Sstevel@tonic-gate static void
1663*7c478bd9Sstevel@tonic-gate order_haddrlist_inet(char **haddrlist, size_t addrcount)
1664*7c478bd9Sstevel@tonic-gate {
1665*7c478bd9Sstevel@tonic-gate 	static struct	ifinfo *localinfo = NULL;
1666*7c478bd9Sstevel@tonic-gate 	static hrtime_t	then = 0; /* the last time localinfo was updated */
1667*7c478bd9Sstevel@tonic-gate 	hrtime_t	now;
1668*7c478bd9Sstevel@tonic-gate 	static rwlock_t	localinfo_lock = DEFAULTRWLOCK;
1669*7c478bd9Sstevel@tonic-gate 	uint8_t		*sortbuf;
1670*7c478bd9Sstevel@tonic-gate 	size_t		sortbuf_size;
1671*7c478bd9Sstevel@tonic-gate 	struct in_addr	**inaddrlist = (struct in_addr **)haddrlist;
1672*7c478bd9Sstevel@tonic-gate 	struct in_addr	**sorted;
1673*7c478bd9Sstevel@tonic-gate 	struct in_addr	**classnext[ADDR_NUMCLASSES];
1674*7c478bd9Sstevel@tonic-gate 	uint_t		classcount[ADDR_NUMCLASSES];
1675*7c478bd9Sstevel@tonic-gate 	addr_class_t	*sortclass;
1676*7c478bd9Sstevel@tonic-gate 	int		i;
1677*7c478bd9Sstevel@tonic-gate 	int		rc;
1678*7c478bd9Sstevel@tonic-gate 
1679*7c478bd9Sstevel@tonic-gate 
1680*7c478bd9Sstevel@tonic-gate 	/*
1681*7c478bd9Sstevel@tonic-gate 	 * The classes in the sortclass array correspond to the class
1682*7c478bd9Sstevel@tonic-gate 	 * of the address in the haddrlist list of the same index.
1683*7c478bd9Sstevel@tonic-gate 	 * The classes are:
1684*7c478bd9Sstevel@tonic-gate 	 *
1685*7c478bd9Sstevel@tonic-gate 	 * ADDR_ONLINK	on-link address
1686*7c478bd9Sstevel@tonic-gate 	 * ADDR_OFFLINK	off-link address
1687*7c478bd9Sstevel@tonic-gate 	 */
1688*7c478bd9Sstevel@tonic-gate 	sortbuf_size = addrcount *
1689*7c478bd9Sstevel@tonic-gate 	    (sizeof (struct in_addr *) + sizeof (addr_class_t));
1690*7c478bd9Sstevel@tonic-gate 	if ((sortbuf = malloc(sortbuf_size)) == NULL)
1691*7c478bd9Sstevel@tonic-gate 		return;
1692*7c478bd9Sstevel@tonic-gate 	sorted = (struct in_addr **)sortbuf;
1693*7c478bd9Sstevel@tonic-gate 	sortclass = (addr_class_t *)(sortbuf +
1694*7c478bd9Sstevel@tonic-gate 	    (addrcount * sizeof (struct in_addr *)));
1695*7c478bd9Sstevel@tonic-gate 
1696*7c478bd9Sstevel@tonic-gate 	/*
1697*7c478bd9Sstevel@tonic-gate 	 * Get a read lock, and check if the interface information
1698*7c478bd9Sstevel@tonic-gate 	 * is too old.
1699*7c478bd9Sstevel@tonic-gate 	 */
1700*7c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&localinfo_lock);
1701*7c478bd9Sstevel@tonic-gate 	now = gethrtime();
1702*7c478bd9Sstevel@tonic-gate 	if (localinfo == NULL || ((now - then) > IFINFOTIMEOUT)) {
1703*7c478bd9Sstevel@tonic-gate 		/* Need to update I/F info. Upgrade to write lock. */
1704*7c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&localinfo_lock);
1705*7c478bd9Sstevel@tonic-gate 		(void) rw_wrlock(&localinfo_lock);
1706*7c478bd9Sstevel@tonic-gate 		/*
1707*7c478bd9Sstevel@tonic-gate 		 * Another thread might have updated "then" between
1708*7c478bd9Sstevel@tonic-gate 		 * the rw_unlock() and rw_wrlock() calls above, so
1709*7c478bd9Sstevel@tonic-gate 		 * re-check the timeout.
1710*7c478bd9Sstevel@tonic-gate 		 */
1711*7c478bd9Sstevel@tonic-gate 		if (localinfo == NULL || ((now - then) > IFINFOTIMEOUT)) {
1712*7c478bd9Sstevel@tonic-gate 			if (localinfo != NULL)
1713*7c478bd9Sstevel@tonic-gate 				free(localinfo);
1714*7c478bd9Sstevel@tonic-gate 			if ((localinfo = get_local_info()) == NULL) {
1715*7c478bd9Sstevel@tonic-gate 				(void) rw_unlock(&localinfo_lock);
1716*7c478bd9Sstevel@tonic-gate 				free(sortbuf);
1717*7c478bd9Sstevel@tonic-gate 				return;
1718*7c478bd9Sstevel@tonic-gate 			}
1719*7c478bd9Sstevel@tonic-gate 			then = now;
1720*7c478bd9Sstevel@tonic-gate 		}
1721*7c478bd9Sstevel@tonic-gate 		/* Downgrade to read lock */
1722*7c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&localinfo_lock);
1723*7c478bd9Sstevel@tonic-gate 		(void) rw_rdlock(&localinfo_lock);
1724*7c478bd9Sstevel@tonic-gate 		/*
1725*7c478bd9Sstevel@tonic-gate 		 * Another thread may have updated the I/F info,
1726*7c478bd9Sstevel@tonic-gate 		 * so verify that the 'localinfo' pointer still
1727*7c478bd9Sstevel@tonic-gate 		 * is non-NULL.
1728*7c478bd9Sstevel@tonic-gate 		 */
1729*7c478bd9Sstevel@tonic-gate 		if (localinfo == NULL) {
1730*7c478bd9Sstevel@tonic-gate 			(void) rw_unlock(&localinfo_lock);
1731*7c478bd9Sstevel@tonic-gate 			free(sortbuf);
1732*7c478bd9Sstevel@tonic-gate 			return;
1733*7c478bd9Sstevel@tonic-gate 		}
1734*7c478bd9Sstevel@tonic-gate 	}
1735*7c478bd9Sstevel@tonic-gate 
1736*7c478bd9Sstevel@tonic-gate 	/*
1737*7c478bd9Sstevel@tonic-gate 	 * Classify the addresses.  We also maintain the classcount
1738*7c478bd9Sstevel@tonic-gate 	 * array to keep track of the number of addresses in each
1739*7c478bd9Sstevel@tonic-gate 	 * class.
1740*7c478bd9Sstevel@tonic-gate 	 */
1741*7c478bd9Sstevel@tonic-gate 	memset(classcount, 0, sizeof (classcount));
1742*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < addrcount; i++) {
1743*7c478bd9Sstevel@tonic-gate 		if (__inet_address_is_local_af(localinfo, AF_INET,
1744*7c478bd9Sstevel@tonic-gate 		    inaddrlist[i]))
1745*7c478bd9Sstevel@tonic-gate 			sortclass[i] = ADDR_ONLINK;
1746*7c478bd9Sstevel@tonic-gate 		else
1747*7c478bd9Sstevel@tonic-gate 			sortclass[i] = ADDR_OFFLINK;
1748*7c478bd9Sstevel@tonic-gate 		classcount[sortclass[i]]++;
1749*7c478bd9Sstevel@tonic-gate 	}
1750*7c478bd9Sstevel@tonic-gate 
1751*7c478bd9Sstevel@tonic-gate 	/* Don't need the interface list anymore in this call */
1752*7c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&localinfo_lock);
1753*7c478bd9Sstevel@tonic-gate 
1754*7c478bd9Sstevel@tonic-gate 	/*
1755*7c478bd9Sstevel@tonic-gate 	 * Each element in the classnext array points to the next
1756*7c478bd9Sstevel@tonic-gate 	 * element for that class in the sorted address list. 'rc' is
1757*7c478bd9Sstevel@tonic-gate 	 * the running count of elements as we sum the class
1758*7c478bd9Sstevel@tonic-gate 	 * sub-totals.
1759*7c478bd9Sstevel@tonic-gate 	 */
1760*7c478bd9Sstevel@tonic-gate 	for (rc = 0, i = 0; i < ADDR_NUMCLASSES; i++) {
1761*7c478bd9Sstevel@tonic-gate 		classnext[i] = &sorted[rc];
1762*7c478bd9Sstevel@tonic-gate 		rc += classcount[i];
1763*7c478bd9Sstevel@tonic-gate 	}
1764*7c478bd9Sstevel@tonic-gate 
1765*7c478bd9Sstevel@tonic-gate 	/* Now for the actual rearrangement of the addresses */
1766*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < addrcount; i++) {
1767*7c478bd9Sstevel@tonic-gate 		*(classnext[sortclass[i]]) = inaddrlist[i];
1768*7c478bd9Sstevel@tonic-gate 		classnext[sortclass[i]]++;
1769*7c478bd9Sstevel@tonic-gate 	}
1770*7c478bd9Sstevel@tonic-gate 
1771*7c478bd9Sstevel@tonic-gate 	/* Copy the sorted list to inaddrlist */
1772*7c478bd9Sstevel@tonic-gate 	(void) memcpy(inaddrlist, sorted,
1773*7c478bd9Sstevel@tonic-gate 	    addrcount * sizeof (struct in_addr *));
1774*7c478bd9Sstevel@tonic-gate 	free(sortbuf);
1775*7c478bd9Sstevel@tonic-gate }
1776*7c478bd9Sstevel@tonic-gate 
1777*7c478bd9Sstevel@tonic-gate /*
1778*7c478bd9Sstevel@tonic-gate  * This function implements the IPv6 Default Address Selection's
1779*7c478bd9Sstevel@tonic-gate  * destination address ordering mechanism.  The algorithm is described
1780*7c478bd9Sstevel@tonic-gate  * in getaddrinfo(3SOCKET).
1781*7c478bd9Sstevel@tonic-gate  */
1782*7c478bd9Sstevel@tonic-gate static void
1783*7c478bd9Sstevel@tonic-gate order_haddrlist_inet6(char **haddrlist, size_t addrcount)
1784*7c478bd9Sstevel@tonic-gate {
1785*7c478bd9Sstevel@tonic-gate 	struct dstinforeq *dinfo, *dinfoptr;
1786*7c478bd9Sstevel@tonic-gate 	int index;
1787*7c478bd9Sstevel@tonic-gate 	struct in6_addr **in6addrlist = (struct in6_addr **)haddrlist;
1788*7c478bd9Sstevel@tonic-gate 	struct in6_addr	**in6addr;
1789*7c478bd9Sstevel@tonic-gate 
1790*7c478bd9Sstevel@tonic-gate 	if ((dinfo = calloc(addrcount, sizeof (struct dstinforeq))) == NULL)
1791*7c478bd9Sstevel@tonic-gate 		return;
1792*7c478bd9Sstevel@tonic-gate 
1793*7c478bd9Sstevel@tonic-gate 	/* Initialize the dstinfo array we'll use for SIOCGDSTINFO */
1794*7c478bd9Sstevel@tonic-gate 	dinfoptr = dinfo;
1795*7c478bd9Sstevel@tonic-gate 	for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) {
1796*7c478bd9Sstevel@tonic-gate 		dinfoptr->dir_daddr = **in6addr;
1797*7c478bd9Sstevel@tonic-gate 		dinfoptr++;
1798*7c478bd9Sstevel@tonic-gate 	}
1799*7c478bd9Sstevel@tonic-gate 
1800*7c478bd9Sstevel@tonic-gate 	if (nss_strioctl(AF_INET6, SIOCGDSTINFO, dinfo,
1801*7c478bd9Sstevel@tonic-gate 	    addrcount * sizeof (struct dstinforeq)) < 0) {
1802*7c478bd9Sstevel@tonic-gate 		free(dinfo);
1803*7c478bd9Sstevel@tonic-gate 		return;
1804*7c478bd9Sstevel@tonic-gate 	}
1805*7c478bd9Sstevel@tonic-gate 
1806*7c478bd9Sstevel@tonic-gate 	/* Sort the dinfo array */
1807*7c478bd9Sstevel@tonic-gate 	qsort(dinfo, addrcount, sizeof (struct dstinforeq), dstcmp);
1808*7c478bd9Sstevel@tonic-gate 
1809*7c478bd9Sstevel@tonic-gate 	/* Copy the addresses back into in6addrlist */
1810*7c478bd9Sstevel@tonic-gate 	dinfoptr = dinfo;
1811*7c478bd9Sstevel@tonic-gate 	for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) {
1812*7c478bd9Sstevel@tonic-gate 		**in6addr = dinfoptr->dir_daddr;
1813*7c478bd9Sstevel@tonic-gate 		dinfoptr++;
1814*7c478bd9Sstevel@tonic-gate 	}
1815*7c478bd9Sstevel@tonic-gate 
1816*7c478bd9Sstevel@tonic-gate 	free(dinfo);
1817*7c478bd9Sstevel@tonic-gate }
1818*7c478bd9Sstevel@tonic-gate 
1819*7c478bd9Sstevel@tonic-gate /*
1820*7c478bd9Sstevel@tonic-gate  * Determine number of leading bits that are common between two addresses.
1821*7c478bd9Sstevel@tonic-gate  * Only consider bits which fall within the prefix length plen.
1822*7c478bd9Sstevel@tonic-gate  */
1823*7c478bd9Sstevel@tonic-gate static uint_t
1824*7c478bd9Sstevel@tonic-gate ip_addr_commonbits_v6(const in6_addr_t *a1, const in6_addr_t *a2)
1825*7c478bd9Sstevel@tonic-gate {
1826*7c478bd9Sstevel@tonic-gate 	uint_t		bits;
1827*7c478bd9Sstevel@tonic-gate 	uint_t		i;
1828*7c478bd9Sstevel@tonic-gate 	uint32_t	diff;	/* Bits that differ */
1829*7c478bd9Sstevel@tonic-gate 
1830*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 4; i++) {
1831*7c478bd9Sstevel@tonic-gate 		if (a1->_S6_un._S6_u32[i] != a2->_S6_un._S6_u32[i])
1832*7c478bd9Sstevel@tonic-gate 			break;
1833*7c478bd9Sstevel@tonic-gate 	}
1834*7c478bd9Sstevel@tonic-gate 	bits = i * 32;
1835*7c478bd9Sstevel@tonic-gate 
1836*7c478bd9Sstevel@tonic-gate 	if (bits == IPV6_ABITS)
1837*7c478bd9Sstevel@tonic-gate 		return (IPV6_ABITS);
1838*7c478bd9Sstevel@tonic-gate 
1839*7c478bd9Sstevel@tonic-gate 	/*
1840*7c478bd9Sstevel@tonic-gate 	 * Find number of leading common bits in the word which might
1841*7c478bd9Sstevel@tonic-gate 	 * have some common bits by searching for the first one from the left
1842*7c478bd9Sstevel@tonic-gate 	 * in the xor of the two addresses.
1843*7c478bd9Sstevel@tonic-gate 	 */
1844*7c478bd9Sstevel@tonic-gate 	diff = ntohl(a1->_S6_un._S6_u32[i] ^ a2->_S6_un._S6_u32[i]);
1845*7c478bd9Sstevel@tonic-gate 	if (diff & 0xffff0000ul)
1846*7c478bd9Sstevel@tonic-gate 		diff >>= 16;
1847*7c478bd9Sstevel@tonic-gate 	else
1848*7c478bd9Sstevel@tonic-gate 		bits += 16;
1849*7c478bd9Sstevel@tonic-gate 	if (diff & 0xff00)
1850*7c478bd9Sstevel@tonic-gate 		diff >>= 8;
1851*7c478bd9Sstevel@tonic-gate 	else
1852*7c478bd9Sstevel@tonic-gate 		bits += 8;
1853*7c478bd9Sstevel@tonic-gate 	if (diff & 0xf0)
1854*7c478bd9Sstevel@tonic-gate 		diff >>= 4;
1855*7c478bd9Sstevel@tonic-gate 	else
1856*7c478bd9Sstevel@tonic-gate 		bits += 4;
1857*7c478bd9Sstevel@tonic-gate 	if (diff & 0xc)
1858*7c478bd9Sstevel@tonic-gate 		diff >>= 2;
1859*7c478bd9Sstevel@tonic-gate 	else
1860*7c478bd9Sstevel@tonic-gate 		bits += 2;
1861*7c478bd9Sstevel@tonic-gate 	if (!(diff & 2))
1862*7c478bd9Sstevel@tonic-gate 		bits++;
1863*7c478bd9Sstevel@tonic-gate 
1864*7c478bd9Sstevel@tonic-gate 	/*
1865*7c478bd9Sstevel@tonic-gate 	 * We don't need to shift and check for the last bit.  The
1866*7c478bd9Sstevel@tonic-gate 	 * check for IPV6_ABITS above would have caught that.
1867*7c478bd9Sstevel@tonic-gate 	 */
1868*7c478bd9Sstevel@tonic-gate 
1869*7c478bd9Sstevel@tonic-gate 	return (bits);
1870*7c478bd9Sstevel@tonic-gate }
1871*7c478bd9Sstevel@tonic-gate 
1872*7c478bd9Sstevel@tonic-gate 
1873*7c478bd9Sstevel@tonic-gate /*
1874*7c478bd9Sstevel@tonic-gate  * The following group of functions named rule_*() are individual
1875*7c478bd9Sstevel@tonic-gate  * sorting rules for the AF_INET6 address sorting algorithm.  The
1876*7c478bd9Sstevel@tonic-gate  * functions compare two addresses (described by two dstinforeq
1877*7c478bd9Sstevel@tonic-gate  * structures), and determines if one is "greater" than the other, or
1878*7c478bd9Sstevel@tonic-gate  * if the two are equal according to that rule.
1879*7c478bd9Sstevel@tonic-gate  */
1880*7c478bd9Sstevel@tonic-gate typedef	int (*rulef_t)(const struct dstinforeq *, const struct dstinforeq *);
1881*7c478bd9Sstevel@tonic-gate 
1882*7c478bd9Sstevel@tonic-gate /*
1883*7c478bd9Sstevel@tonic-gate  * These values of these constants are no accident.  Since qsort()
1884*7c478bd9Sstevel@tonic-gate  * implements the AF_INET6 address sorting, the comparison function
1885*7c478bd9Sstevel@tonic-gate  * must return an integer less than, equal to, or greater than zero to
1886*7c478bd9Sstevel@tonic-gate  * indicate if the first address is considered "less than", "equal
1887*7c478bd9Sstevel@tonic-gate  * to", or "greater than" the second one.  Since we want the best
1888*7c478bd9Sstevel@tonic-gate  * addresses first on the list, "less than" is considered preferrable.
1889*7c478bd9Sstevel@tonic-gate  */
1890*7c478bd9Sstevel@tonic-gate #define	RULE_PREFER_DA	-1
1891*7c478bd9Sstevel@tonic-gate #define	RULE_PREFER_DB	1
1892*7c478bd9Sstevel@tonic-gate #define	RULE_EQUAL	0
1893*7c478bd9Sstevel@tonic-gate 
1894*7c478bd9Sstevel@tonic-gate /* Prefer the addresses that is reachable. */
1895*7c478bd9Sstevel@tonic-gate static int
1896*7c478bd9Sstevel@tonic-gate rule_reachable(const struct dstinforeq *da, const struct dstinforeq *db)
1897*7c478bd9Sstevel@tonic-gate {
1898*7c478bd9Sstevel@tonic-gate 	if (da->dir_dreachable == db->dir_dreachable)
1899*7c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
1900*7c478bd9Sstevel@tonic-gate 	if (da->dir_dreachable)
1901*7c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
1902*7c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
1903*7c478bd9Sstevel@tonic-gate }
1904*7c478bd9Sstevel@tonic-gate 
1905*7c478bd9Sstevel@tonic-gate /* Prefer the address whose scope matches that of its source address. */
1906*7c478bd9Sstevel@tonic-gate static int
1907*7c478bd9Sstevel@tonic-gate rule_matchscope(const struct dstinforeq *da, const struct dstinforeq *db)
1908*7c478bd9Sstevel@tonic-gate {
1909*7c478bd9Sstevel@tonic-gate 	boolean_t da_scope_match, db_scope_match;
1910*7c478bd9Sstevel@tonic-gate 
1911*7c478bd9Sstevel@tonic-gate 	da_scope_match = da->dir_dscope == da->dir_sscope;
1912*7c478bd9Sstevel@tonic-gate 	db_scope_match = db->dir_dscope == db->dir_sscope;
1913*7c478bd9Sstevel@tonic-gate 
1914*7c478bd9Sstevel@tonic-gate 	if (da_scope_match == db_scope_match)
1915*7c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
1916*7c478bd9Sstevel@tonic-gate 	if (da_scope_match)
1917*7c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
1918*7c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
1919*7c478bd9Sstevel@tonic-gate }
1920*7c478bd9Sstevel@tonic-gate 
1921*7c478bd9Sstevel@tonic-gate /* Avoid the address with the link local source address. */
1922*7c478bd9Sstevel@tonic-gate static int
1923*7c478bd9Sstevel@tonic-gate rule_avoidlinklocal(const struct dstinforeq *da, const struct dstinforeq *db)
1924*7c478bd9Sstevel@tonic-gate {
1925*7c478bd9Sstevel@tonic-gate 	if (da->dir_sscope == IP6_SCOPE_LINKLOCAL &&
1926*7c478bd9Sstevel@tonic-gate 	    da->dir_dscope != IP6_SCOPE_LINKLOCAL &&
1927*7c478bd9Sstevel@tonic-gate 	    db->dir_sscope != IP6_SCOPE_LINKLOCAL)
1928*7c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DB);
1929*7c478bd9Sstevel@tonic-gate 	if (db->dir_sscope == IP6_SCOPE_LINKLOCAL &&
1930*7c478bd9Sstevel@tonic-gate 	    db->dir_dscope != IP6_SCOPE_LINKLOCAL &&
1931*7c478bd9Sstevel@tonic-gate 	    da->dir_sscope != IP6_SCOPE_LINKLOCAL)
1932*7c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
1933*7c478bd9Sstevel@tonic-gate 	return (RULE_EQUAL);
1934*7c478bd9Sstevel@tonic-gate }
1935*7c478bd9Sstevel@tonic-gate 
1936*7c478bd9Sstevel@tonic-gate /* Prefer the address whose source address isn't deprecated. */
1937*7c478bd9Sstevel@tonic-gate static int
1938*7c478bd9Sstevel@tonic-gate rule_deprecated(const struct dstinforeq *da, const struct dstinforeq *db)
1939*7c478bd9Sstevel@tonic-gate {
1940*7c478bd9Sstevel@tonic-gate 	if (da->dir_sdeprecated == db->dir_sdeprecated)
1941*7c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
1942*7c478bd9Sstevel@tonic-gate 	if (db->dir_sdeprecated)
1943*7c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
1944*7c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
1945*7c478bd9Sstevel@tonic-gate }
1946*7c478bd9Sstevel@tonic-gate 
1947*7c478bd9Sstevel@tonic-gate /* Prefer the address whose label matches that of its source address. */
1948*7c478bd9Sstevel@tonic-gate static int
1949*7c478bd9Sstevel@tonic-gate rule_label(const struct dstinforeq *da, const struct dstinforeq *db)
1950*7c478bd9Sstevel@tonic-gate {
1951*7c478bd9Sstevel@tonic-gate 	if (da->dir_labelmatch == db->dir_labelmatch)
1952*7c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
1953*7c478bd9Sstevel@tonic-gate 	if (da->dir_labelmatch)
1954*7c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
1955*7c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
1956*7c478bd9Sstevel@tonic-gate }
1957*7c478bd9Sstevel@tonic-gate 
1958*7c478bd9Sstevel@tonic-gate /* Prefer the address with the higher precedence. */
1959*7c478bd9Sstevel@tonic-gate static int
1960*7c478bd9Sstevel@tonic-gate rule_precedence(const struct dstinforeq *da, const struct dstinforeq *db)
1961*7c478bd9Sstevel@tonic-gate {
1962*7c478bd9Sstevel@tonic-gate 	if (da->dir_precedence == db->dir_precedence)
1963*7c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
1964*7c478bd9Sstevel@tonic-gate 	if (da->dir_precedence > db->dir_precedence)
1965*7c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
1966*7c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
1967*7c478bd9Sstevel@tonic-gate }
1968*7c478bd9Sstevel@tonic-gate 
1969*7c478bd9Sstevel@tonic-gate /* Prefer the address whose output interface isn't an IP tunnel */
1970*7c478bd9Sstevel@tonic-gate static int
1971*7c478bd9Sstevel@tonic-gate rule_native(const struct dstinforeq *da, const struct dstinforeq *db)
1972*7c478bd9Sstevel@tonic-gate {
1973*7c478bd9Sstevel@tonic-gate 	boolean_t isatun, isbtun;
1974*7c478bd9Sstevel@tonic-gate 
1975*7c478bd9Sstevel@tonic-gate 	/* Get the common case out of the way early */
1976*7c478bd9Sstevel@tonic-gate 	if (da->dir_dmactype == db->dir_dmactype)
1977*7c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
1978*7c478bd9Sstevel@tonic-gate 
1979*7c478bd9Sstevel@tonic-gate 	isatun = da->dir_dmactype == DL_IPV4 || da->dir_dmactype == DL_IPV6;
1980*7c478bd9Sstevel@tonic-gate 	isbtun = db->dir_dmactype == DL_IPV4 || db->dir_dmactype == DL_IPV6;
1981*7c478bd9Sstevel@tonic-gate 
1982*7c478bd9Sstevel@tonic-gate 	if (isatun == isbtun)
1983*7c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
1984*7c478bd9Sstevel@tonic-gate 	if (isbtun)
1985*7c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
1986*7c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
1987*7c478bd9Sstevel@tonic-gate }
1988*7c478bd9Sstevel@tonic-gate 
1989*7c478bd9Sstevel@tonic-gate /* Prefer the address with the smaller scope. */
1990*7c478bd9Sstevel@tonic-gate static int
1991*7c478bd9Sstevel@tonic-gate rule_scope(const struct dstinforeq *da, const struct dstinforeq *db)
1992*7c478bd9Sstevel@tonic-gate {
1993*7c478bd9Sstevel@tonic-gate 	if (da->dir_dscope == db->dir_dscope)
1994*7c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
1995*7c478bd9Sstevel@tonic-gate 	if (da->dir_dscope < db->dir_dscope)
1996*7c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
1997*7c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
1998*7c478bd9Sstevel@tonic-gate }
1999*7c478bd9Sstevel@tonic-gate 
2000*7c478bd9Sstevel@tonic-gate /*
2001*7c478bd9Sstevel@tonic-gate  * Prefer the address that has the most leading bits in common with its
2002*7c478bd9Sstevel@tonic-gate  * source address.
2003*7c478bd9Sstevel@tonic-gate  */
2004*7c478bd9Sstevel@tonic-gate static int
2005*7c478bd9Sstevel@tonic-gate rule_prefix(const struct dstinforeq *da, const struct dstinforeq *db)
2006*7c478bd9Sstevel@tonic-gate {
2007*7c478bd9Sstevel@tonic-gate 	uint_t da_commonbits, db_commonbits;
2008*7c478bd9Sstevel@tonic-gate 	boolean_t da_isipv4, db_isipv4;
2009*7c478bd9Sstevel@tonic-gate 
2010*7c478bd9Sstevel@tonic-gate 	da_isipv4 = IN6_IS_ADDR_V4MAPPED(&da->dir_daddr);
2011*7c478bd9Sstevel@tonic-gate 	db_isipv4 = IN6_IS_ADDR_V4MAPPED(&db->dir_daddr);
2012*7c478bd9Sstevel@tonic-gate 
2013*7c478bd9Sstevel@tonic-gate 	/*
2014*7c478bd9Sstevel@tonic-gate 	 * At this point, the order doesn't matter if the two addresses
2015*7c478bd9Sstevel@tonic-gate 	 * aren't of the same address family.
2016*7c478bd9Sstevel@tonic-gate 	 */
2017*7c478bd9Sstevel@tonic-gate 	if (da_isipv4 != db_isipv4)
2018*7c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
2019*7c478bd9Sstevel@tonic-gate 
2020*7c478bd9Sstevel@tonic-gate 	da_commonbits = ip_addr_commonbits_v6(&da->dir_daddr, &da->dir_saddr);
2021*7c478bd9Sstevel@tonic-gate 	db_commonbits = ip_addr_commonbits_v6(&db->dir_daddr, &db->dir_saddr);
2022*7c478bd9Sstevel@tonic-gate 
2023*7c478bd9Sstevel@tonic-gate 	if (da_commonbits > db_commonbits)
2024*7c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
2025*7c478bd9Sstevel@tonic-gate 	if (da_commonbits < db_commonbits)
2026*7c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DB);
2027*7c478bd9Sstevel@tonic-gate 	return (RULE_EQUAL);
2028*7c478bd9Sstevel@tonic-gate }
2029*7c478bd9Sstevel@tonic-gate 
2030*7c478bd9Sstevel@tonic-gate /*
2031*7c478bd9Sstevel@tonic-gate  * This is the function passed to qsort() that does the AF_INET6
2032*7c478bd9Sstevel@tonic-gate  * address comparisons.  It compares two addresses using a list of
2033*7c478bd9Sstevel@tonic-gate  * rules.  The rules are applied in order until one prefers one
2034*7c478bd9Sstevel@tonic-gate  * address over the other.
2035*7c478bd9Sstevel@tonic-gate  */
2036*7c478bd9Sstevel@tonic-gate static int
2037*7c478bd9Sstevel@tonic-gate dstcmp(const void *da, const void *db)
2038*7c478bd9Sstevel@tonic-gate {
2039*7c478bd9Sstevel@tonic-gate 	int index, result;
2040*7c478bd9Sstevel@tonic-gate 	rulef_t rules[] = {
2041*7c478bd9Sstevel@tonic-gate 		rule_reachable,
2042*7c478bd9Sstevel@tonic-gate 		rule_matchscope,
2043*7c478bd9Sstevel@tonic-gate 		rule_avoidlinklocal,
2044*7c478bd9Sstevel@tonic-gate 		rule_deprecated,
2045*7c478bd9Sstevel@tonic-gate 		rule_label,
2046*7c478bd9Sstevel@tonic-gate 		rule_precedence,
2047*7c478bd9Sstevel@tonic-gate 		rule_native,
2048*7c478bd9Sstevel@tonic-gate 		rule_scope,
2049*7c478bd9Sstevel@tonic-gate 		rule_prefix,
2050*7c478bd9Sstevel@tonic-gate 		NULL
2051*7c478bd9Sstevel@tonic-gate 	};
2052*7c478bd9Sstevel@tonic-gate 
2053*7c478bd9Sstevel@tonic-gate 	result = 0;
2054*7c478bd9Sstevel@tonic-gate 	for (index = 0; rules[index] != NULL; index++) {
2055*7c478bd9Sstevel@tonic-gate 		result = (rules[index])(da, db);
2056*7c478bd9Sstevel@tonic-gate 		if (result != RULE_EQUAL)
2057*7c478bd9Sstevel@tonic-gate 			break;
2058*7c478bd9Sstevel@tonic-gate 	}
2059*7c478bd9Sstevel@tonic-gate 
2060*7c478bd9Sstevel@tonic-gate 	return (result);
2061*7c478bd9Sstevel@tonic-gate }
2062*7c478bd9Sstevel@tonic-gate 
2063*7c478bd9Sstevel@tonic-gate /*
2064*7c478bd9Sstevel@tonic-gate  * Given haddrlist and a port number, mallocs and populates a new
2065*7c478bd9Sstevel@tonic-gate  * nd_addrlist.  The new nd_addrlist maintains the order of the addresses
2066*7c478bd9Sstevel@tonic-gate  * in haddrlist, which have already been sorted by order_haddrlist_inet()
2067*7c478bd9Sstevel@tonic-gate  * or order_haddrlist_inet6().  For IPv6 this function filters out
2068*7c478bd9Sstevel@tonic-gate  * IPv4-mapped IPv6 addresses.
2069*7c478bd9Sstevel@tonic-gate  */
2070*7c478bd9Sstevel@tonic-gate int
2071*7c478bd9Sstevel@tonic-gate hent2ndaddr(int af, char **haddrlist, int *servp, struct nd_addrlist **nd_alist)
2072*7c478bd9Sstevel@tonic-gate {
2073*7c478bd9Sstevel@tonic-gate 	struct nd_addrlist	*result;
2074*7c478bd9Sstevel@tonic-gate 	int			num;
2075*7c478bd9Sstevel@tonic-gate 	struct netbuf		*na;
2076*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sinbuf, *sin;
2077*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6buf, *sin6;
2078*7c478bd9Sstevel@tonic-gate 	struct in_addr		**inaddr, **inaddrlist;
2079*7c478bd9Sstevel@tonic-gate 	struct in6_addr		**in6addr, **in6addrlist;
2080*7c478bd9Sstevel@tonic-gate 
2081*7c478bd9Sstevel@tonic-gate 	/* Address count */
2082*7c478bd9Sstevel@tonic-gate 	num = 0;
2083*7c478bd9Sstevel@tonic-gate 	if (af == AF_INET6) {
2084*7c478bd9Sstevel@tonic-gate 		in6addrlist = (struct in6_addr **)haddrlist;
2085*7c478bd9Sstevel@tonic-gate 
2086*7c478bd9Sstevel@tonic-gate 		/*
2087*7c478bd9Sstevel@tonic-gate 		 * Exclude IPv4-mapped IPv6 addresses from the count, as
2088*7c478bd9Sstevel@tonic-gate 		 * these are not included in the nd_addrlist we return.
2089*7c478bd9Sstevel@tonic-gate 		 */
2090*7c478bd9Sstevel@tonic-gate 		for (in6addr = in6addrlist; *in6addr != NULL; in6addr++)
2091*7c478bd9Sstevel@tonic-gate 			if (!IN6_IS_ADDR_V4MAPPED(*in6addr))
2092*7c478bd9Sstevel@tonic-gate 				num++;
2093*7c478bd9Sstevel@tonic-gate 	} else {
2094*7c478bd9Sstevel@tonic-gate 		inaddrlist = (struct in_addr **)haddrlist;
2095*7c478bd9Sstevel@tonic-gate 
2096*7c478bd9Sstevel@tonic-gate 		for (inaddr = inaddrlist; *inaddr != NULL; inaddr++)
2097*7c478bd9Sstevel@tonic-gate 			num++;
2098*7c478bd9Sstevel@tonic-gate 	}
2099*7c478bd9Sstevel@tonic-gate 	if (num == 0)
2100*7c478bd9Sstevel@tonic-gate 		return (ND_NOHOST);
2101*7c478bd9Sstevel@tonic-gate 
2102*7c478bd9Sstevel@tonic-gate 	result = malloc(sizeof (struct nd_addrlist));
2103*7c478bd9Sstevel@tonic-gate 	if (result == 0)
2104*7c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
2105*7c478bd9Sstevel@tonic-gate 
2106*7c478bd9Sstevel@tonic-gate 	result->n_cnt = num;
2107*7c478bd9Sstevel@tonic-gate 	result->n_addrs = calloc(num, sizeof (struct netbuf));
2108*7c478bd9Sstevel@tonic-gate 	if (result->n_addrs == 0) {
2109*7c478bd9Sstevel@tonic-gate 		free(result);
2110*7c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
2111*7c478bd9Sstevel@tonic-gate 	}
2112*7c478bd9Sstevel@tonic-gate 
2113*7c478bd9Sstevel@tonic-gate 	na = result->n_addrs;
2114*7c478bd9Sstevel@tonic-gate 	if (af == AF_INET) {
2115*7c478bd9Sstevel@tonic-gate 		sinbuf = calloc(num, sizeof (struct sockaddr_in));
2116*7c478bd9Sstevel@tonic-gate 		if (sinbuf == NULL) {
2117*7c478bd9Sstevel@tonic-gate 			free(result->n_addrs);
2118*7c478bd9Sstevel@tonic-gate 			free(result);
2119*7c478bd9Sstevel@tonic-gate 			return (ND_NOMEM);
2120*7c478bd9Sstevel@tonic-gate 		}
2121*7c478bd9Sstevel@tonic-gate 
2122*7c478bd9Sstevel@tonic-gate 		sin = sinbuf;
2123*7c478bd9Sstevel@tonic-gate 		for (inaddr = inaddrlist; *inaddr != NULL; inaddr++) {
2124*7c478bd9Sstevel@tonic-gate 			na->len = na->maxlen = sizeof (struct sockaddr_in);
2125*7c478bd9Sstevel@tonic-gate 			na->buf = (char *)sin;
2126*7c478bd9Sstevel@tonic-gate 			sin->sin_family = AF_INET;
2127*7c478bd9Sstevel@tonic-gate 			sin->sin_addr = **inaddr;
2128*7c478bd9Sstevel@tonic-gate 			sin->sin_port = *servp;
2129*7c478bd9Sstevel@tonic-gate 			na++;
2130*7c478bd9Sstevel@tonic-gate 			sin++;
2131*7c478bd9Sstevel@tonic-gate 		}
2132*7c478bd9Sstevel@tonic-gate 	} else if (af == AF_INET6) {
2133*7c478bd9Sstevel@tonic-gate 		sin6buf = calloc(num, sizeof (struct sockaddr_in6));
2134*7c478bd9Sstevel@tonic-gate 		if (sin6buf == NULL) {
2135*7c478bd9Sstevel@tonic-gate 			free(result->n_addrs);
2136*7c478bd9Sstevel@tonic-gate 			free(result);
2137*7c478bd9Sstevel@tonic-gate 			return (ND_NOMEM);
2138*7c478bd9Sstevel@tonic-gate 		}
2139*7c478bd9Sstevel@tonic-gate 
2140*7c478bd9Sstevel@tonic-gate 		sin6 = sin6buf;
2141*7c478bd9Sstevel@tonic-gate 		for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) {
2142*7c478bd9Sstevel@tonic-gate 			if (IN6_IS_ADDR_V4MAPPED(*in6addr))
2143*7c478bd9Sstevel@tonic-gate 				continue;
2144*7c478bd9Sstevel@tonic-gate 
2145*7c478bd9Sstevel@tonic-gate 			na->len = na->maxlen = sizeof (struct sockaddr_in6);
2146*7c478bd9Sstevel@tonic-gate 			na->buf = (char *)sin6;
2147*7c478bd9Sstevel@tonic-gate 			sin6->sin6_family = AF_INET6;
2148*7c478bd9Sstevel@tonic-gate 			sin6->sin6_addr = **in6addr;
2149*7c478bd9Sstevel@tonic-gate 			sin6->sin6_port = *servp;
2150*7c478bd9Sstevel@tonic-gate 			na++;
2151*7c478bd9Sstevel@tonic-gate 			sin6++;
2152*7c478bd9Sstevel@tonic-gate 		}
2153*7c478bd9Sstevel@tonic-gate 	}
2154*7c478bd9Sstevel@tonic-gate 	*(nd_alist) = result;
2155*7c478bd9Sstevel@tonic-gate 	return (ND_OK);
2156*7c478bd9Sstevel@tonic-gate }
2157*7c478bd9Sstevel@tonic-gate 
2158*7c478bd9Sstevel@tonic-gate /*
2159*7c478bd9Sstevel@tonic-gate  * Given a hostent and a servent, mallocs and populates
2160*7c478bd9Sstevel@tonic-gate  * a new nd_hostservlist with host and service names.
2161*7c478bd9Sstevel@tonic-gate  *
2162*7c478bd9Sstevel@tonic-gate  * We could be passed in a NULL servent, in which case stringify port.
2163*7c478bd9Sstevel@tonic-gate  */
2164*7c478bd9Sstevel@tonic-gate int
2165*7c478bd9Sstevel@tonic-gate hsents2ndhostservs(struct hostent *he, struct servent *se,
2166*7c478bd9Sstevel@tonic-gate     ushort_t port, struct nd_hostservlist **hslist)
2167*7c478bd9Sstevel@tonic-gate {
2168*7c478bd9Sstevel@tonic-gate 	struct	nd_hostservlist *result;
2169*7c478bd9Sstevel@tonic-gate 	struct	nd_hostserv *hs;
2170*7c478bd9Sstevel@tonic-gate 	int	hosts, servs, i, j;
2171*7c478bd9Sstevel@tonic-gate 	char	**hn, **sn;
2172*7c478bd9Sstevel@tonic-gate 
2173*7c478bd9Sstevel@tonic-gate 	if ((result = (struct nd_hostservlist *)
2174*7c478bd9Sstevel@tonic-gate 		    malloc(sizeof (struct nd_hostservlist))) == 0)
2175*7c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
2176*7c478bd9Sstevel@tonic-gate 
2177*7c478bd9Sstevel@tonic-gate 	/*
2178*7c478bd9Sstevel@tonic-gate 	 * We initialize the counters to 1 rather than zero because
2179*7c478bd9Sstevel@tonic-gate 	 * we have to count the "official" name as well as the aliases.
2180*7c478bd9Sstevel@tonic-gate 	 */
2181*7c478bd9Sstevel@tonic-gate 	for (hn = he->h_aliases, hosts = 1; hn && *hn; hn++, hosts++);
2182*7c478bd9Sstevel@tonic-gate 	if (se)
2183*7c478bd9Sstevel@tonic-gate 		for (sn = se->s_aliases, servs = 1; sn && *sn; sn++, servs++);
2184*7c478bd9Sstevel@tonic-gate 	else
2185*7c478bd9Sstevel@tonic-gate 		servs = 1;
2186*7c478bd9Sstevel@tonic-gate 
2187*7c478bd9Sstevel@tonic-gate 	if ((hs = (struct nd_hostserv *)calloc(hosts * servs,
2188*7c478bd9Sstevel@tonic-gate 			sizeof (struct nd_hostserv))) == 0) {
2189*7c478bd9Sstevel@tonic-gate 		free((void *)result);
2190*7c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
2191*7c478bd9Sstevel@tonic-gate 	}
2192*7c478bd9Sstevel@tonic-gate 
2193*7c478bd9Sstevel@tonic-gate 	result->h_cnt	= servs * hosts;
2194*7c478bd9Sstevel@tonic-gate 	result->h_hostservs = hs;
2195*7c478bd9Sstevel@tonic-gate 
2196*7c478bd9Sstevel@tonic-gate 	for (i = 0, hn = he->h_aliases; i < hosts; i++) {
2197*7c478bd9Sstevel@tonic-gate 		sn = se ? se->s_aliases : NULL;
2198*7c478bd9Sstevel@tonic-gate 
2199*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < servs; j++) {
2200*7c478bd9Sstevel@tonic-gate 			if (i == 0)
2201*7c478bd9Sstevel@tonic-gate 				hs->h_host = strdup(he->h_name);
2202*7c478bd9Sstevel@tonic-gate 			else
2203*7c478bd9Sstevel@tonic-gate 				hs->h_host = strdup(*hn);
2204*7c478bd9Sstevel@tonic-gate 			if (j == 0) {
2205*7c478bd9Sstevel@tonic-gate 				if (se)
2206*7c478bd9Sstevel@tonic-gate 					hs->h_serv = strdup(se->s_name);
2207*7c478bd9Sstevel@tonic-gate 				else {
2208*7c478bd9Sstevel@tonic-gate 					/* Convert to a number string */
2209*7c478bd9Sstevel@tonic-gate 					char stmp[16];
2210*7c478bd9Sstevel@tonic-gate 
2211*7c478bd9Sstevel@tonic-gate 					(void) sprintf(stmp, "%d", port);
2212*7c478bd9Sstevel@tonic-gate 					hs->h_serv = strdup(stmp);
2213*7c478bd9Sstevel@tonic-gate 				}
2214*7c478bd9Sstevel@tonic-gate 			} else
2215*7c478bd9Sstevel@tonic-gate 				hs->h_serv = strdup(*sn++);
2216*7c478bd9Sstevel@tonic-gate 
2217*7c478bd9Sstevel@tonic-gate 			if ((hs->h_host == 0) || (hs->h_serv == 0)) {
2218*7c478bd9Sstevel@tonic-gate 				free((void *)result->h_hostservs);
2219*7c478bd9Sstevel@tonic-gate 				free((void *)result);
2220*7c478bd9Sstevel@tonic-gate 				return (ND_NOMEM);
2221*7c478bd9Sstevel@tonic-gate 			}
2222*7c478bd9Sstevel@tonic-gate 			hs++;
2223*7c478bd9Sstevel@tonic-gate 		}
2224*7c478bd9Sstevel@tonic-gate 		if (i)
2225*7c478bd9Sstevel@tonic-gate 			hn++;
2226*7c478bd9Sstevel@tonic-gate 	}
2227*7c478bd9Sstevel@tonic-gate 	*(hslist) = result;
2228*7c478bd9Sstevel@tonic-gate 	return (ND_OK);
2229*7c478bd9Sstevel@tonic-gate }
2230*7c478bd9Sstevel@tonic-gate 
2231*7c478bd9Sstevel@tonic-gate /*
2232*7c478bd9Sstevel@tonic-gate  * Process results from nd_addrlist ( returned by netdir_getbyname)
2233*7c478bd9Sstevel@tonic-gate  * into a hostent using buf.
2234*7c478bd9Sstevel@tonic-gate  * *** ASSUMES that nd_addrlist->n_addrs->buf contains IP addresses in
2235*7c478bd9Sstevel@tonic-gate  * sockaddr_in's ***
2236*7c478bd9Sstevel@tonic-gate  */
2237*7c478bd9Sstevel@tonic-gate int
2238*7c478bd9Sstevel@tonic-gate ndaddr2hent(int af, const char *nam, struct nd_addrlist *addrs,
2239*7c478bd9Sstevel@tonic-gate     struct hostent *result, char *buffer, int buflen)
2240*7c478bd9Sstevel@tonic-gate {
2241*7c478bd9Sstevel@tonic-gate 	int	i, count;
2242*7c478bd9Sstevel@tonic-gate 	struct	in_addr *addrp;
2243*7c478bd9Sstevel@tonic-gate 	struct	in6_addr *addr6p;
2244*7c478bd9Sstevel@tonic-gate 	char	**addrvec;
2245*7c478bd9Sstevel@tonic-gate 	struct	netbuf *na;
2246*7c478bd9Sstevel@tonic-gate 	size_t	len;
2247*7c478bd9Sstevel@tonic-gate 
2248*7c478bd9Sstevel@tonic-gate 	result->h_name		= buffer;
2249*7c478bd9Sstevel@tonic-gate 	result->h_addrtype	= af;
2250*7c478bd9Sstevel@tonic-gate 	result->h_length	= (af == AF_INET) ? sizeof (*addrp):
2251*7c478bd9Sstevel@tonic-gate 						    sizeof (*addr6p);
2252*7c478bd9Sstevel@tonic-gate 
2253*7c478bd9Sstevel@tonic-gate 	/*
2254*7c478bd9Sstevel@tonic-gate 	 * Build addrlist at start of buffer (after name);  store the
2255*7c478bd9Sstevel@tonic-gate 	 * addresses themselves at the end of the buffer.
2256*7c478bd9Sstevel@tonic-gate 	 */
2257*7c478bd9Sstevel@tonic-gate 	len = strlen(nam) + 1;
2258*7c478bd9Sstevel@tonic-gate 	addrvec = (char **)ROUND_UP(buffer + len, sizeof (*addrvec));
2259*7c478bd9Sstevel@tonic-gate 	result->h_addr_list 	= addrvec;
2260*7c478bd9Sstevel@tonic-gate 
2261*7c478bd9Sstevel@tonic-gate 	if (af == AF_INET) {
2262*7c478bd9Sstevel@tonic-gate 		addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen,
2263*7c478bd9Sstevel@tonic-gate 		    sizeof (*addrp));
2264*7c478bd9Sstevel@tonic-gate 
2265*7c478bd9Sstevel@tonic-gate 		count = addrs->n_cnt;
2266*7c478bd9Sstevel@tonic-gate 		if ((char *)(&addrvec[count + 1]) > (char *)(&addrp[-count]))
2267*7c478bd9Sstevel@tonic-gate 			return (ND_NOMEM);
2268*7c478bd9Sstevel@tonic-gate 
2269*7c478bd9Sstevel@tonic-gate 		(void) memcpy(buffer, nam, len);
2270*7c478bd9Sstevel@tonic-gate 
2271*7c478bd9Sstevel@tonic-gate 		for (na = addrs->n_addrs, i = 0;  i < count;  na++, i++) {
2272*7c478bd9Sstevel@tonic-gate 			--addrp;
2273*7c478bd9Sstevel@tonic-gate 			(void) memcpy(addrp,
2274*7c478bd9Sstevel@tonic-gate 			    &((struct sockaddr_in *)na->buf)->sin_addr,
2275*7c478bd9Sstevel@tonic-gate 			    sizeof (*addrp));
2276*7c478bd9Sstevel@tonic-gate 			*addrvec++ = (char *)addrp;
2277*7c478bd9Sstevel@tonic-gate 		}
2278*7c478bd9Sstevel@tonic-gate 	} else {
2279*7c478bd9Sstevel@tonic-gate 		addr6p = (struct in6_addr *)ROUND_DOWN(buffer + buflen,
2280*7c478bd9Sstevel@tonic-gate 			sizeof (*addr6p));
2281*7c478bd9Sstevel@tonic-gate 
2282*7c478bd9Sstevel@tonic-gate 		count = addrs->n_cnt;
2283*7c478bd9Sstevel@tonic-gate 		if ((char *)(&addrvec[count + 1]) > (char *)(&addr6p[-count]))
2284*7c478bd9Sstevel@tonic-gate 			return (ND_NOMEM);
2285*7c478bd9Sstevel@tonic-gate 
2286*7c478bd9Sstevel@tonic-gate 		(void) memcpy(buffer, nam, len);
2287*7c478bd9Sstevel@tonic-gate 
2288*7c478bd9Sstevel@tonic-gate 		for (na = addrs->n_addrs, i = 0;  i < count;  na++, i++) {
2289*7c478bd9Sstevel@tonic-gate 			--addr6p;
2290*7c478bd9Sstevel@tonic-gate 			(void) memcpy(addr6p,
2291*7c478bd9Sstevel@tonic-gate 			    &((struct sockaddr_in6 *)na->buf)->sin6_addr,
2292*7c478bd9Sstevel@tonic-gate 			    sizeof (*addr6p));
2293*7c478bd9Sstevel@tonic-gate 			*addrvec++ = (char *)addr6p;
2294*7c478bd9Sstevel@tonic-gate 		}
2295*7c478bd9Sstevel@tonic-gate 	}
2296*7c478bd9Sstevel@tonic-gate 	*addrvec = 0;
2297*7c478bd9Sstevel@tonic-gate 	result->h_aliases = addrvec;
2298*7c478bd9Sstevel@tonic-gate 
2299*7c478bd9Sstevel@tonic-gate 	return (ND_OK);
2300*7c478bd9Sstevel@tonic-gate }
2301*7c478bd9Sstevel@tonic-gate 
2302*7c478bd9Sstevel@tonic-gate /*
2303*7c478bd9Sstevel@tonic-gate  * Process results from nd_addrlist ( returned by netdir_getbyname)
2304*7c478bd9Sstevel@tonic-gate  * into a servent using buf.
2305*7c478bd9Sstevel@tonic-gate  */
2306*7c478bd9Sstevel@tonic-gate int
2307*7c478bd9Sstevel@tonic-gate ndaddr2srent(const char *name, const char *proto, ushort_t port,
2308*7c478bd9Sstevel@tonic-gate     struct servent *result, char *buffer, int buflen)
2309*7c478bd9Sstevel@tonic-gate {
2310*7c478bd9Sstevel@tonic-gate 	size_t	i;
2311*7c478bd9Sstevel@tonic-gate 	char	*bufend = (buffer + buflen);
2312*7c478bd9Sstevel@tonic-gate 
2313*7c478bd9Sstevel@tonic-gate 	result->s_port = (int)port;
2314*7c478bd9Sstevel@tonic-gate 
2315*7c478bd9Sstevel@tonic-gate 	result->s_aliases =
2316*7c478bd9Sstevel@tonic-gate 	    (char **)ROUND_UP(buffer, sizeof (char *));
2317*7c478bd9Sstevel@tonic-gate 	result->s_aliases[0] = NULL;
2318*7c478bd9Sstevel@tonic-gate 	buffer = (char *)&result->s_aliases[1];
2319*7c478bd9Sstevel@tonic-gate 	result->s_name = buffer;
2320*7c478bd9Sstevel@tonic-gate 	i = strlen(name) + 1;
2321*7c478bd9Sstevel@tonic-gate 	if ((buffer + i) > bufend)
2322*7c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
2323*7c478bd9Sstevel@tonic-gate 	(void) memcpy(buffer, name, i);
2324*7c478bd9Sstevel@tonic-gate 	buffer += i;
2325*7c478bd9Sstevel@tonic-gate 
2326*7c478bd9Sstevel@tonic-gate 	result->s_proto	= buffer;
2327*7c478bd9Sstevel@tonic-gate 	i = strlen(proto) + 1;
2328*7c478bd9Sstevel@tonic-gate 	if ((buffer + i) > bufend)
2329*7c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
2330*7c478bd9Sstevel@tonic-gate 	(void) memcpy(buffer, proto, i);
2331*7c478bd9Sstevel@tonic-gate 	buffer += i;
2332*7c478bd9Sstevel@tonic-gate 
2333*7c478bd9Sstevel@tonic-gate 	return (ND_OK);
2334*7c478bd9Sstevel@tonic-gate }
2335*7c478bd9Sstevel@tonic-gate 
2336*7c478bd9Sstevel@tonic-gate /*
2337*7c478bd9Sstevel@tonic-gate  * Process results from nd_hostservlist ( returned by netdir_getbyaddr)
2338*7c478bd9Sstevel@tonic-gate  * into a hostent using buf.
2339*7c478bd9Sstevel@tonic-gate  * *** ASSUMES that nd_buf->buf is a sockaddr_in ***
2340*7c478bd9Sstevel@tonic-gate  */
2341*7c478bd9Sstevel@tonic-gate int
2342*7c478bd9Sstevel@tonic-gate ndhostserv2hent(struct netbuf *nbuf, struct nd_hostservlist *addrs,
2343*7c478bd9Sstevel@tonic-gate     struct hostent *result, char *buffer, int buflen)
2344*7c478bd9Sstevel@tonic-gate {
2345*7c478bd9Sstevel@tonic-gate 	int	i, count;
2346*7c478bd9Sstevel@tonic-gate 	char	*aliasp;
2347*7c478bd9Sstevel@tonic-gate 	char	**aliasvec;
2348*7c478bd9Sstevel@tonic-gate 	struct	sockaddr_in *sa;
2349*7c478bd9Sstevel@tonic-gate 	struct	nd_hostserv *hs;
2350*7c478bd9Sstevel@tonic-gate 	const	char *la;
2351*7c478bd9Sstevel@tonic-gate 	size_t	length;
2352*7c478bd9Sstevel@tonic-gate 
2353*7c478bd9Sstevel@tonic-gate 	/* First, give the lonely address a specious home in h_addr_list. */
2354*7c478bd9Sstevel@tonic-gate 	aliasp   = (char  *)ROUND_UP(buffer, sizeof (sa->sin_addr));
2355*7c478bd9Sstevel@tonic-gate 	sa = (struct sockaddr_in *)nbuf->buf;
2356*7c478bd9Sstevel@tonic-gate 	(void) memcpy(aliasp, (char *)&(sa->sin_addr), sizeof (sa->sin_addr));
2357*7c478bd9Sstevel@tonic-gate 	aliasvec = (char **)ROUND_UP(aliasp + sizeof (sa->sin_addr),
2358*7c478bd9Sstevel@tonic-gate 		sizeof (*aliasvec));
2359*7c478bd9Sstevel@tonic-gate 	result->h_addr_list = aliasvec;
2360*7c478bd9Sstevel@tonic-gate 	*aliasvec++ = aliasp;
2361*7c478bd9Sstevel@tonic-gate 	*aliasvec++ = 0;
2362*7c478bd9Sstevel@tonic-gate 
2363*7c478bd9Sstevel@tonic-gate 	/*
2364*7c478bd9Sstevel@tonic-gate 	 * Build h_aliases at start of buffer (after addr and h_addr_list);
2365*7c478bd9Sstevel@tonic-gate 	 * store the alias strings at the end of the buffer (before h_name).
2366*7c478bd9Sstevel@tonic-gate 	 */
2367*7c478bd9Sstevel@tonic-gate 
2368*7c478bd9Sstevel@tonic-gate 	aliasp = buffer + buflen;
2369*7c478bd9Sstevel@tonic-gate 
2370*7c478bd9Sstevel@tonic-gate 	result->h_aliases	= aliasvec;
2371*7c478bd9Sstevel@tonic-gate 
2372*7c478bd9Sstevel@tonic-gate 	hs = addrs->h_hostservs;
2373*7c478bd9Sstevel@tonic-gate 	if (! hs)
2374*7c478bd9Sstevel@tonic-gate 		return (ND_NOHOST);
2375*7c478bd9Sstevel@tonic-gate 
2376*7c478bd9Sstevel@tonic-gate 	length = strlen(hs->h_host) + 1;
2377*7c478bd9Sstevel@tonic-gate 	aliasp -= length;
2378*7c478bd9Sstevel@tonic-gate 	if ((char *)(&aliasvec[1]) > aliasp)
2379*7c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
2380*7c478bd9Sstevel@tonic-gate 	(void) memcpy(aliasp, hs->h_host, length);
2381*7c478bd9Sstevel@tonic-gate 
2382*7c478bd9Sstevel@tonic-gate 	result->h_name		= aliasp;
2383*7c478bd9Sstevel@tonic-gate 	result->h_addrtype	= AF_INET;
2384*7c478bd9Sstevel@tonic-gate 	result->h_length	= sizeof (sa->sin_addr);
2385*7c478bd9Sstevel@tonic-gate 
2386*7c478bd9Sstevel@tonic-gate 	/*
2387*7c478bd9Sstevel@tonic-gate 	 * Assumption: the netdir nametoaddr_libs
2388*7c478bd9Sstevel@tonic-gate 	 * sort the vector of (host, serv) pairs in such a way that
2389*7c478bd9Sstevel@tonic-gate 	 * all pairs with the same host name are contiguous.
2390*7c478bd9Sstevel@tonic-gate 	 */
2391*7c478bd9Sstevel@tonic-gate 	la = hs->h_host;
2392*7c478bd9Sstevel@tonic-gate 	count = addrs->h_cnt;
2393*7c478bd9Sstevel@tonic-gate 	for (i = 0;  i < count;  i++, hs++)
2394*7c478bd9Sstevel@tonic-gate 		if (strcmp(la, hs->h_host) != 0) {
2395*7c478bd9Sstevel@tonic-gate 			size_t len = strlen(hs->h_host) + 1;
2396*7c478bd9Sstevel@tonic-gate 
2397*7c478bd9Sstevel@tonic-gate 			aliasp -= len;
2398*7c478bd9Sstevel@tonic-gate 			if ((char *)(&aliasvec[2]) > aliasp)
2399*7c478bd9Sstevel@tonic-gate 				return (ND_NOMEM);
2400*7c478bd9Sstevel@tonic-gate 			(void) memcpy(aliasp, hs->h_host, len);
2401*7c478bd9Sstevel@tonic-gate 			*aliasvec++ = aliasp;
2402*7c478bd9Sstevel@tonic-gate 			la = hs->h_host;
2403*7c478bd9Sstevel@tonic-gate 		}
2404*7c478bd9Sstevel@tonic-gate 	*aliasvec = 0;
2405*7c478bd9Sstevel@tonic-gate 
2406*7c478bd9Sstevel@tonic-gate 	return (ND_OK);
2407*7c478bd9Sstevel@tonic-gate }
2408*7c478bd9Sstevel@tonic-gate 
2409*7c478bd9Sstevel@tonic-gate /*
2410*7c478bd9Sstevel@tonic-gate  * Process results from nd_hostservlist ( returned by netdir_getbyaddr)
2411*7c478bd9Sstevel@tonic-gate  * into a servent using buf.
2412*7c478bd9Sstevel@tonic-gate  */
2413*7c478bd9Sstevel@tonic-gate int
2414*7c478bd9Sstevel@tonic-gate ndhostserv2srent(int port, const char *proto, struct nd_hostservlist *addrs,
2415*7c478bd9Sstevel@tonic-gate     struct servent *result, char *buffer, int buflen)
2416*7c478bd9Sstevel@tonic-gate {
2417*7c478bd9Sstevel@tonic-gate 	int	i, count;
2418*7c478bd9Sstevel@tonic-gate 	char	*aliasp;
2419*7c478bd9Sstevel@tonic-gate 	char	**aliasvec;
2420*7c478bd9Sstevel@tonic-gate 	struct	nd_hostserv *hs;
2421*7c478bd9Sstevel@tonic-gate 	const	char *host_cname;
2422*7c478bd9Sstevel@tonic-gate 	size_t	leni, lenj;
2423*7c478bd9Sstevel@tonic-gate 
2424*7c478bd9Sstevel@tonic-gate 	result->s_port = port;
2425*7c478bd9Sstevel@tonic-gate 	/*
2426*7c478bd9Sstevel@tonic-gate 	 * Build s_aliases at start of buffer;
2427*7c478bd9Sstevel@tonic-gate 	 * store proto and aliases at the end of the buffer (before h_name).
2428*7c478bd9Sstevel@tonic-gate 	 */
2429*7c478bd9Sstevel@tonic-gate 
2430*7c478bd9Sstevel@tonic-gate 	aliasp = buffer + buflen;
2431*7c478bd9Sstevel@tonic-gate 	aliasvec = (char **)ROUND_UP(buffer, sizeof (char *));
2432*7c478bd9Sstevel@tonic-gate 
2433*7c478bd9Sstevel@tonic-gate 	result->s_aliases	= aliasvec;
2434*7c478bd9Sstevel@tonic-gate 
2435*7c478bd9Sstevel@tonic-gate 	hs = addrs->h_hostservs;
2436*7c478bd9Sstevel@tonic-gate 	if (! hs)
2437*7c478bd9Sstevel@tonic-gate 		return (ND_NOHOST);
2438*7c478bd9Sstevel@tonic-gate 	host_cname = hs->h_host;
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate 	leni = strlen(proto) + 1;
2441*7c478bd9Sstevel@tonic-gate 	lenj = strlen(hs->h_serv) + 1;
2442*7c478bd9Sstevel@tonic-gate 	if ((char *)(&aliasvec[2]) > (aliasp - leni - lenj))
2443*7c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
2444*7c478bd9Sstevel@tonic-gate 
2445*7c478bd9Sstevel@tonic-gate 	aliasp -= leni;
2446*7c478bd9Sstevel@tonic-gate 	(void) memcpy(aliasp, proto, leni);
2447*7c478bd9Sstevel@tonic-gate 	result->s_proto = aliasp;
2448*7c478bd9Sstevel@tonic-gate 
2449*7c478bd9Sstevel@tonic-gate 	aliasp -= lenj;
2450*7c478bd9Sstevel@tonic-gate 	(void) memcpy(aliasp, hs->h_serv, lenj);
2451*7c478bd9Sstevel@tonic-gate 	result->s_name = aliasp;
2452*7c478bd9Sstevel@tonic-gate 
2453*7c478bd9Sstevel@tonic-gate 	/*
2454*7c478bd9Sstevel@tonic-gate 	 * Assumption: the netdir nametoaddr_libs
2455*7c478bd9Sstevel@tonic-gate 	 * do a host aliases first and serv aliases next
2456*7c478bd9Sstevel@tonic-gate 	 * enumeration for creating the list of hostserv
2457*7c478bd9Sstevel@tonic-gate 	 * structures.
2458*7c478bd9Sstevel@tonic-gate 	 */
2459*7c478bd9Sstevel@tonic-gate 	count = addrs->h_cnt;
2460*7c478bd9Sstevel@tonic-gate 	for (i = 0;
2461*7c478bd9Sstevel@tonic-gate 	    i < count && hs->h_serv && strcmp(hs->h_host, host_cname) == 0;
2462*7c478bd9Sstevel@tonic-gate 	    i++, hs++) {
2463*7c478bd9Sstevel@tonic-gate 		size_t len = strlen(hs->h_serv) + 1;
2464*7c478bd9Sstevel@tonic-gate 
2465*7c478bd9Sstevel@tonic-gate 		aliasp -= len;
2466*7c478bd9Sstevel@tonic-gate 		if ((char *)(&aliasvec[2]) > aliasp)
2467*7c478bd9Sstevel@tonic-gate 			return (ND_NOMEM);
2468*7c478bd9Sstevel@tonic-gate 		(void) memcpy(aliasp, hs->h_serv, len);
2469*7c478bd9Sstevel@tonic-gate 		*aliasvec++ = aliasp;
2470*7c478bd9Sstevel@tonic-gate 	}
2471*7c478bd9Sstevel@tonic-gate 	*aliasvec = NULL;
2472*7c478bd9Sstevel@tonic-gate 
2473*7c478bd9Sstevel@tonic-gate 	return (ND_OK);
2474*7c478bd9Sstevel@tonic-gate }
2475*7c478bd9Sstevel@tonic-gate 
2476*7c478bd9Sstevel@tonic-gate 
2477*7c478bd9Sstevel@tonic-gate static int
2478*7c478bd9Sstevel@tonic-gate nd2herrno(int nerr)
2479*7c478bd9Sstevel@tonic-gate {
2480*7c478bd9Sstevel@tonic-gate 	trace1(TR_nd2herrno, 0);
2481*7c478bd9Sstevel@tonic-gate 	switch (nerr) {
2482*7c478bd9Sstevel@tonic-gate 	case ND_OK:
2483*7c478bd9Sstevel@tonic-gate 		trace1(TR_nd2herrno, 1);
2484*7c478bd9Sstevel@tonic-gate 		return (0);
2485*7c478bd9Sstevel@tonic-gate 	case ND_TRY_AGAIN:
2486*7c478bd9Sstevel@tonic-gate 		trace1(TR_nd2herrno, 1);
2487*7c478bd9Sstevel@tonic-gate 		return (TRY_AGAIN);
2488*7c478bd9Sstevel@tonic-gate 	case ND_NO_RECOVERY:
2489*7c478bd9Sstevel@tonic-gate 	case ND_BADARG:
2490*7c478bd9Sstevel@tonic-gate 	case ND_NOMEM:
2491*7c478bd9Sstevel@tonic-gate 		trace1(TR_nd2herrno, 1);
2492*7c478bd9Sstevel@tonic-gate 		return (NO_RECOVERY);
2493*7c478bd9Sstevel@tonic-gate 	case ND_NO_DATA:
2494*7c478bd9Sstevel@tonic-gate 		trace1(TR_nd2herrno, 1);
2495*7c478bd9Sstevel@tonic-gate 		return (NO_DATA);
2496*7c478bd9Sstevel@tonic-gate 	case ND_NOHOST:
2497*7c478bd9Sstevel@tonic-gate 	case ND_NOSERV:
2498*7c478bd9Sstevel@tonic-gate 		trace1(TR_nd2herrno, 1);
2499*7c478bd9Sstevel@tonic-gate 		return (HOST_NOT_FOUND);
2500*7c478bd9Sstevel@tonic-gate 	default:
2501*7c478bd9Sstevel@tonic-gate 		trace1(TR_nd2herrno, 1);
2502*7c478bd9Sstevel@tonic-gate 		return (NO_RECOVERY);
2503*7c478bd9Sstevel@tonic-gate 	}
2504*7c478bd9Sstevel@tonic-gate }
2505*7c478bd9Sstevel@tonic-gate 
2506*7c478bd9Sstevel@tonic-gate /*
2507*7c478bd9Sstevel@tonic-gate  * This is a utility function so that various parts of libnsl can
2508*7c478bd9Sstevel@tonic-gate  * easily send ioctls down to ip.
2509*7c478bd9Sstevel@tonic-gate  *
2510*7c478bd9Sstevel@tonic-gate  */
2511*7c478bd9Sstevel@tonic-gate int
2512*7c478bd9Sstevel@tonic-gate nss_ioctl(int af, int cmd, void *arg)
2513*7c478bd9Sstevel@tonic-gate {
2514*7c478bd9Sstevel@tonic-gate 	int	fd;
2515*7c478bd9Sstevel@tonic-gate 	char	*devpath;
2516*7c478bd9Sstevel@tonic-gate 	int	retv;
2517*7c478bd9Sstevel@tonic-gate 
2518*7c478bd9Sstevel@tonic-gate 	switch (af) {
2519*7c478bd9Sstevel@tonic-gate 	case AF_INET6:
2520*7c478bd9Sstevel@tonic-gate 		devpath = UDP6DEV;
2521*7c478bd9Sstevel@tonic-gate 		break;
2522*7c478bd9Sstevel@tonic-gate 	case AF_INET:
2523*7c478bd9Sstevel@tonic-gate 	case AF_UNSPEC:
2524*7c478bd9Sstevel@tonic-gate 	default:
2525*7c478bd9Sstevel@tonic-gate 		devpath = UDPDEV;
2526*7c478bd9Sstevel@tonic-gate 	}
2527*7c478bd9Sstevel@tonic-gate 	if ((fd = open(devpath, O_RDONLY)) < 0) {
2528*7c478bd9Sstevel@tonic-gate 		return (-1);
2529*7c478bd9Sstevel@tonic-gate 	}
2530*7c478bd9Sstevel@tonic-gate 	while ((retv = ioctl(fd, cmd, arg)) == -1) {
2531*7c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
2532*7c478bd9Sstevel@tonic-gate 	break;
2533*7c478bd9Sstevel@tonic-gate 	}
2534*7c478bd9Sstevel@tonic-gate 	close(fd);
2535*7c478bd9Sstevel@tonic-gate 	return (retv);
2536*7c478bd9Sstevel@tonic-gate }
2537*7c478bd9Sstevel@tonic-gate 
2538*7c478bd9Sstevel@tonic-gate static int
2539*7c478bd9Sstevel@tonic-gate nss_strioctl(int af, int cmd, void *ptr, int ilen)
2540*7c478bd9Sstevel@tonic-gate {
2541*7c478bd9Sstevel@tonic-gate 	struct strioctl str;
2542*7c478bd9Sstevel@tonic-gate 
2543*7c478bd9Sstevel@tonic-gate 	str.ic_cmd = cmd;
2544*7c478bd9Sstevel@tonic-gate 	str.ic_timout = 0;
2545*7c478bd9Sstevel@tonic-gate 	str.ic_len = ilen;
2546*7c478bd9Sstevel@tonic-gate 	str.ic_dp = ptr;
2547*7c478bd9Sstevel@tonic-gate 
2548*7c478bd9Sstevel@tonic-gate 	return (nss_ioctl(af, I_STR, &str));
2549*7c478bd9Sstevel@tonic-gate }
2550*7c478bd9Sstevel@tonic-gate 
2551*7c478bd9Sstevel@tonic-gate static struct ifinfo *
2552*7c478bd9Sstevel@tonic-gate get_local_info(void)
2553*7c478bd9Sstevel@tonic-gate {
2554*7c478bd9Sstevel@tonic-gate 	int	numifs;
2555*7c478bd9Sstevel@tonic-gate 	int	n;
2556*7c478bd9Sstevel@tonic-gate 	char	*buf = NULL;
2557*7c478bd9Sstevel@tonic-gate 	size_t	needed;
2558*7c478bd9Sstevel@tonic-gate 	struct lifconf	lifc;
2559*7c478bd9Sstevel@tonic-gate 	struct lifreq	lifreq, *lifr;
2560*7c478bd9Sstevel@tonic-gate 	struct lifnum	lifn;
2561*7c478bd9Sstevel@tonic-gate 	struct ifinfo	*localinfo;
2562*7c478bd9Sstevel@tonic-gate 
2563*7c478bd9Sstevel@tonic-gate 	lifn.lifn_family = AF_UNSPEC;
2564*7c478bd9Sstevel@tonic-gate 	lifn.lifn_flags = 0;
2565*7c478bd9Sstevel@tonic-gate 
2566*7c478bd9Sstevel@tonic-gate getifnum:
2567*7c478bd9Sstevel@tonic-gate 	if (nss_ioctl(AF_UNSPEC, SIOCGLIFNUM, &lifn) == -1) {
2568*7c478bd9Sstevel@tonic-gate 		numifs = MAXIFS;
2569*7c478bd9Sstevel@tonic-gate 	} else {
2570*7c478bd9Sstevel@tonic-gate 		numifs = lifn.lifn_count;
2571*7c478bd9Sstevel@tonic-gate 	}
2572*7c478bd9Sstevel@tonic-gate 
2573*7c478bd9Sstevel@tonic-gate 	/*
2574*7c478bd9Sstevel@tonic-gate 	 * Add a small fudge factor in case interfaces get plumbed between
2575*7c478bd9Sstevel@tonic-gate 	 * the call to SIOCGLIFNUM and SIOCGLIFCONF.
2576*7c478bd9Sstevel@tonic-gate 	 */
2577*7c478bd9Sstevel@tonic-gate 	needed = (numifs + 4) * sizeof (lifreq);
2578*7c478bd9Sstevel@tonic-gate 	if (buf == NULL)
2579*7c478bd9Sstevel@tonic-gate 		buf = malloc(needed);
2580*7c478bd9Sstevel@tonic-gate 	else
2581*7c478bd9Sstevel@tonic-gate 		buf = realloc(buf, needed);
2582*7c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
2583*7c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m");
2584*7c478bd9Sstevel@tonic-gate 		_nderror = ND_NOMEM;
2585*7c478bd9Sstevel@tonic-gate 		return (NULL);
2586*7c478bd9Sstevel@tonic-gate 	}
2587*7c478bd9Sstevel@tonic-gate 	lifc.lifc_family = AF_UNSPEC;
2588*7c478bd9Sstevel@tonic-gate 	lifc.lifc_flags = 0;
2589*7c478bd9Sstevel@tonic-gate 	lifc.lifc_len = needed;
2590*7c478bd9Sstevel@tonic-gate 	lifc.lifc_buf = buf;
2591*7c478bd9Sstevel@tonic-gate 	if (nss_ioctl(AF_UNSPEC, SIOCGLIFCONF, &lifc) == -1) {
2592*7c478bd9Sstevel@tonic-gate 		/*
2593*7c478bd9Sstevel@tonic-gate 		 * IP returns EINVAL if the buffer was too small to fit
2594*7c478bd9Sstevel@tonic-gate 		 * all of the entries.  If that's the case, go back and
2595*7c478bd9Sstevel@tonic-gate 		 * try again.
2596*7c478bd9Sstevel@tonic-gate 		 */
2597*7c478bd9Sstevel@tonic-gate 		if (errno == EINVAL)
2598*7c478bd9Sstevel@tonic-gate 			goto getifnum;
2599*7c478bd9Sstevel@tonic-gate 
2600*7c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "n2a get_local_info: "
2601*7c478bd9Sstevel@tonic-gate 		    "ioctl (get interface configuration): %m");
2602*7c478bd9Sstevel@tonic-gate 		free(buf);
2603*7c478bd9Sstevel@tonic-gate 		_nderror = ND_SYSTEM;
2604*7c478bd9Sstevel@tonic-gate 		return (NULL);
2605*7c478bd9Sstevel@tonic-gate 	}
2606*7c478bd9Sstevel@tonic-gate 	lifr = (struct lifreq *)buf;
2607*7c478bd9Sstevel@tonic-gate 	numifs = lifc.lifc_len/sizeof (lifreq);
2608*7c478bd9Sstevel@tonic-gate 	localinfo = (struct ifinfo *)malloc(ifinfosize(numifs));
2609*7c478bd9Sstevel@tonic-gate 	if (localinfo == NULL) {
2610*7c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m");
2611*7c478bd9Sstevel@tonic-gate 		free(buf);
2612*7c478bd9Sstevel@tonic-gate 		_nderror = ND_SYSTEM;
2613*7c478bd9Sstevel@tonic-gate 		return (NULL);
2614*7c478bd9Sstevel@tonic-gate 	}
2615*7c478bd9Sstevel@tonic-gate 
2616*7c478bd9Sstevel@tonic-gate 	localinfo->addresses = (struct __ifaddr *)
2617*7c478bd9Sstevel@tonic-gate 	    ((char *)localinfo + sizeof (struct ifinfo));
2618*7c478bd9Sstevel@tonic-gate 
2619*7c478bd9Sstevel@tonic-gate 	for (localinfo->count = 0, n = numifs; n > 0; n--, lifr++) {
2620*7c478bd9Sstevel@tonic-gate 		int af;
2621*7c478bd9Sstevel@tonic-gate 
2622*7c478bd9Sstevel@tonic-gate 		lifreq = *lifr;
2623*7c478bd9Sstevel@tonic-gate 		af = lifreq.lifr_addr.ss_family;
2624*7c478bd9Sstevel@tonic-gate 
2625*7c478bd9Sstevel@tonic-gate 		/* Squirrel away the address */
2626*7c478bd9Sstevel@tonic-gate 		if (ifassign(lifreq, localinfo->count, IF_ADDR) == 0)
2627*7c478bd9Sstevel@tonic-gate 			continue;
2628*7c478bd9Sstevel@tonic-gate 
2629*7c478bd9Sstevel@tonic-gate 		if (nss_ioctl(af, SIOCGLIFFLAGS, &lifreq) < 0) {
2630*7c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
2631*7c478bd9Sstevel@tonic-gate 			    "n2a get_local_info: "
2632*7c478bd9Sstevel@tonic-gate 			    "ioctl (get interface flags): %m");
2633*7c478bd9Sstevel@tonic-gate 			continue;
2634*7c478bd9Sstevel@tonic-gate 		}
2635*7c478bd9Sstevel@tonic-gate 		if (!(lifreq.lifr_flags & IFF_UP))
2636*7c478bd9Sstevel@tonic-gate 			continue;
2637*7c478bd9Sstevel@tonic-gate 
2638*7c478bd9Sstevel@tonic-gate 		if (nss_ioctl(af, SIOCGLIFNETMASK, &lifreq) < 0) {
2639*7c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
2640*7c478bd9Sstevel@tonic-gate 			    "n2a get_local_info: "
2641*7c478bd9Sstevel@tonic-gate 			    "ioctl (get interface netmask): %m");
2642*7c478bd9Sstevel@tonic-gate 			continue;
2643*7c478bd9Sstevel@tonic-gate 		}
2644*7c478bd9Sstevel@tonic-gate 
2645*7c478bd9Sstevel@tonic-gate 		if (ifassign(lifreq, localinfo->count, IF_MASK) == 0)
2646*7c478bd9Sstevel@tonic-gate 			continue;
2647*7c478bd9Sstevel@tonic-gate 
2648*7c478bd9Sstevel@tonic-gate 		localinfo->count++;
2649*7c478bd9Sstevel@tonic-gate 	}
2650*7c478bd9Sstevel@tonic-gate 
2651*7c478bd9Sstevel@tonic-gate 	free(buf);
2652*7c478bd9Sstevel@tonic-gate 	return (localinfo);
2653*7c478bd9Sstevel@tonic-gate }
2654*7c478bd9Sstevel@tonic-gate 
2655*7c478bd9Sstevel@tonic-gate static int
2656*7c478bd9Sstevel@tonic-gate __inet_ifassign(sa_family_t af, struct __ifaddr *ifa, __ifaddr_type type,
2657*7c478bd9Sstevel@tonic-gate     void *addr) {
2658*7c478bd9Sstevel@tonic-gate 	switch (type) {
2659*7c478bd9Sstevel@tonic-gate 	case IF_ADDR:
2660*7c478bd9Sstevel@tonic-gate 		ifa->af = af;
2661*7c478bd9Sstevel@tonic-gate 		if (af == AF_INET6) {
2662*7c478bd9Sstevel@tonic-gate 			ifa->addr.in6 = *(struct in6_addr *)addr;
2663*7c478bd9Sstevel@tonic-gate 		} else {
2664*7c478bd9Sstevel@tonic-gate 			ifa->addr.in4 = *(struct in_addr *)addr;
2665*7c478bd9Sstevel@tonic-gate 		}
2666*7c478bd9Sstevel@tonic-gate 		break;
2667*7c478bd9Sstevel@tonic-gate 	case IF_MASK:
2668*7c478bd9Sstevel@tonic-gate 		if (ifa->af == af) {
2669*7c478bd9Sstevel@tonic-gate 			if (af == AF_INET6) {
2670*7c478bd9Sstevel@tonic-gate 				ifa->mask.in6 = *(struct in6_addr *)addr;
2671*7c478bd9Sstevel@tonic-gate 			} else {
2672*7c478bd9Sstevel@tonic-gate 				ifa->mask.in4 = *(struct in_addr *)addr;
2673*7c478bd9Sstevel@tonic-gate 			}
2674*7c478bd9Sstevel@tonic-gate 		} else {
2675*7c478bd9Sstevel@tonic-gate 			return (0);
2676*7c478bd9Sstevel@tonic-gate 		}
2677*7c478bd9Sstevel@tonic-gate 		break;
2678*7c478bd9Sstevel@tonic-gate 	default:
2679*7c478bd9Sstevel@tonic-gate 		return (0);
2680*7c478bd9Sstevel@tonic-gate 	}
2681*7c478bd9Sstevel@tonic-gate 
2682*7c478bd9Sstevel@tonic-gate 	return (1);
2683*7c478bd9Sstevel@tonic-gate }
2684*7c478bd9Sstevel@tonic-gate 
2685*7c478bd9Sstevel@tonic-gate static int
2686*7c478bd9Sstevel@tonic-gate islocal(struct ifinfo *localinfo, struct in_addr addr)
2687*7c478bd9Sstevel@tonic-gate {
2688*7c478bd9Sstevel@tonic-gate 	int i;
2689*7c478bd9Sstevel@tonic-gate 
2690*7c478bd9Sstevel@tonic-gate 	if (!localinfo)
2691*7c478bd9Sstevel@tonic-gate 	    return (0);
2692*7c478bd9Sstevel@tonic-gate 
2693*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < localinfo->count; i++) {
2694*7c478bd9Sstevel@tonic-gate 		if (ifaf(i) == AF_INET &&
2695*7c478bd9Sstevel@tonic-gate 				((addr.s_addr & ifmask4(i).s_addr) ==
2696*7c478bd9Sstevel@tonic-gate 				(ifaddr4(i).s_addr & ifmask4(i).s_addr)))
2697*7c478bd9Sstevel@tonic-gate 			return (1);
2698*7c478bd9Sstevel@tonic-gate 	}
2699*7c478bd9Sstevel@tonic-gate 	return (0);
2700*7c478bd9Sstevel@tonic-gate }
2701*7c478bd9Sstevel@tonic-gate 
2702*7c478bd9Sstevel@tonic-gate /*
2703*7c478bd9Sstevel@tonic-gate  *  Some higher-level routines for determining if an address is
2704*7c478bd9Sstevel@tonic-gate  *  on a local network.
2705*7c478bd9Sstevel@tonic-gate  *
2706*7c478bd9Sstevel@tonic-gate  *      __inet_get_local_interfaces() - get an opaque handle with
2707*7c478bd9Sstevel@tonic-gate  *          with a list of local interfaces
2708*7c478bd9Sstevel@tonic-gate  *      __inet_address_is_local() - return 1 if an address is
2709*7c478bd9Sstevel@tonic-gate  *          on a local network; 0 otherwise
2710*7c478bd9Sstevel@tonic-gate  *      __inet_free_local_interfaces() - free handle that was
2711*7c478bd9Sstevel@tonic-gate  *          returned by __inet_get_local_interfaces()
2712*7c478bd9Sstevel@tonic-gate  *
2713*7c478bd9Sstevel@tonic-gate  *  A typical calling sequence is:
2714*7c478bd9Sstevel@tonic-gate  *
2715*7c478bd9Sstevel@tonic-gate  *      p = __inet_get_local_interfaces();
2716*7c478bd9Sstevel@tonic-gate  *      if (__inet_address_is_local(p, inaddr)) {
2717*7c478bd9Sstevel@tonic-gate  *          ...
2718*7c478bd9Sstevel@tonic-gate  *      }
2719*7c478bd9Sstevel@tonic-gate  *      __inet_free_local_interfaces(p);
2720*7c478bd9Sstevel@tonic-gate  */
2721*7c478bd9Sstevel@tonic-gate 
2722*7c478bd9Sstevel@tonic-gate /*
2723*7c478bd9Sstevel@tonic-gate  *  Return an opaque pointer to a list of configured interfaces.
2724*7c478bd9Sstevel@tonic-gate  */
2725*7c478bd9Sstevel@tonic-gate void *
2726*7c478bd9Sstevel@tonic-gate __inet_get_local_interfaces(void)
2727*7c478bd9Sstevel@tonic-gate {
2728*7c478bd9Sstevel@tonic-gate 	return (get_local_info());
2729*7c478bd9Sstevel@tonic-gate }
2730*7c478bd9Sstevel@tonic-gate 
2731*7c478bd9Sstevel@tonic-gate /*
2732*7c478bd9Sstevel@tonic-gate  *  Free memory allocated by inet_local_interfaces().
2733*7c478bd9Sstevel@tonic-gate  */
2734*7c478bd9Sstevel@tonic-gate void
2735*7c478bd9Sstevel@tonic-gate __inet_free_local_interfaces(void *p)
2736*7c478bd9Sstevel@tonic-gate {
2737*7c478bd9Sstevel@tonic-gate 	free(p);
2738*7c478bd9Sstevel@tonic-gate }
2739*7c478bd9Sstevel@tonic-gate 
2740*7c478bd9Sstevel@tonic-gate /*
2741*7c478bd9Sstevel@tonic-gate  *  Determine if an address is on a local network.
2742*7c478bd9Sstevel@tonic-gate  *
2743*7c478bd9Sstevel@tonic-gate  *  Might have made sense to use SIOCTONLINK, except that it doesn't
2744*7c478bd9Sstevel@tonic-gate  *  handle matching on IPv4 network addresses.
2745*7c478bd9Sstevel@tonic-gate  */
2746*7c478bd9Sstevel@tonic-gate int
2747*7c478bd9Sstevel@tonic-gate __inet_address_is_local_af(void *p, sa_family_t af, void *addr) {
2748*7c478bd9Sstevel@tonic-gate 
2749*7c478bd9Sstevel@tonic-gate 	struct ifinfo	*localinfo = (struct ifinfo *)p;
2750*7c478bd9Sstevel@tonic-gate 	int		i, a;
2751*7c478bd9Sstevel@tonic-gate 	struct in_addr	v4addr;
2752*7c478bd9Sstevel@tonic-gate 
2753*7c478bd9Sstevel@tonic-gate 	if (localinfo == 0)
2754*7c478bd9Sstevel@tonic-gate 		return (0);
2755*7c478bd9Sstevel@tonic-gate 
2756*7c478bd9Sstevel@tonic-gate 	if (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr)) {
2757*7c478bd9Sstevel@tonic-gate 		IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addr, &v4addr);
2758*7c478bd9Sstevel@tonic-gate 		af = AF_INET;
2759*7c478bd9Sstevel@tonic-gate 		addr = (void *)&v4addr;
2760*7c478bd9Sstevel@tonic-gate 	}
2761*7c478bd9Sstevel@tonic-gate 
2762*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < localinfo->count; i++) {
2763*7c478bd9Sstevel@tonic-gate 		if (ifaf(i) == af) {
2764*7c478bd9Sstevel@tonic-gate 			if (af == AF_INET6) {
2765*7c478bd9Sstevel@tonic-gate 				struct in6_addr *a6 = (struct in6_addr *)addr;
2766*7c478bd9Sstevel@tonic-gate 				for (a = 0; a < sizeof (a6->s6_addr); a++) {
2767*7c478bd9Sstevel@tonic-gate 					if ((a6->s6_addr[a] &
2768*7c478bd9Sstevel@tonic-gate 						ifmask6(i).s6_addr[a]) !=
2769*7c478bd9Sstevel@tonic-gate 						(ifaddr6(i).s6_addr[a] &
2770*7c478bd9Sstevel@tonic-gate 						ifmask6(i).s6_addr[a]))
2771*7c478bd9Sstevel@tonic-gate 						break;
2772*7c478bd9Sstevel@tonic-gate 				}
2773*7c478bd9Sstevel@tonic-gate 				if (a >= sizeof (a6->s6_addr))
2774*7c478bd9Sstevel@tonic-gate 					return (1);
2775*7c478bd9Sstevel@tonic-gate 			} else {
2776*7c478bd9Sstevel@tonic-gate 				if ((((struct in_addr *)addr)->s_addr &
2777*7c478bd9Sstevel@tonic-gate 						ifmask4(i).s_addr) ==
2778*7c478bd9Sstevel@tonic-gate 					(ifaddr4(i).s_addr &
2779*7c478bd9Sstevel@tonic-gate 						ifmask4(i).s_addr))
2780*7c478bd9Sstevel@tonic-gate 					return (1);
2781*7c478bd9Sstevel@tonic-gate 			}
2782*7c478bd9Sstevel@tonic-gate 		}
2783*7c478bd9Sstevel@tonic-gate 	}
2784*7c478bd9Sstevel@tonic-gate 
2785*7c478bd9Sstevel@tonic-gate 	return (0);
2786*7c478bd9Sstevel@tonic-gate }
2787*7c478bd9Sstevel@tonic-gate 
2788*7c478bd9Sstevel@tonic-gate int
2789*7c478bd9Sstevel@tonic-gate __inet_address_is_local(void *p, struct in_addr addr)
2790*7c478bd9Sstevel@tonic-gate {
2791*7c478bd9Sstevel@tonic-gate 	return (__inet_address_is_local_af(p, AF_INET, &addr));
2792*7c478bd9Sstevel@tonic-gate }
2793*7c478bd9Sstevel@tonic-gate 
2794*7c478bd9Sstevel@tonic-gate int
2795*7c478bd9Sstevel@tonic-gate __inet_uaddr_is_local(void *p, struct netconfig *nc, char *uaddr)
2796*7c478bd9Sstevel@tonic-gate {
2797*7c478bd9Sstevel@tonic-gate 	struct netbuf		*taddr;
2798*7c478bd9Sstevel@tonic-gate 	sa_family_t		af;
2799*7c478bd9Sstevel@tonic-gate 	int			ret;
2800*7c478bd9Sstevel@tonic-gate 
2801*7c478bd9Sstevel@tonic-gate 	taddr = uaddr2taddr(nc, uaddr);
2802*7c478bd9Sstevel@tonic-gate 	if (taddr == 0)
2803*7c478bd9Sstevel@tonic-gate 		return (0);
2804*7c478bd9Sstevel@tonic-gate 
2805*7c478bd9Sstevel@tonic-gate 	af = ((struct sockaddr *)taddr->buf)->sa_family;
2806*7c478bd9Sstevel@tonic-gate 
2807*7c478bd9Sstevel@tonic-gate 	ret = __inet_address_is_local_af(p, af,
2808*7c478bd9Sstevel@tonic-gate 		(af == AF_INET6) ?
2809*7c478bd9Sstevel@tonic-gate 		(void *)&((struct sockaddr_in6 *)taddr->buf)->sin6_addr :
2810*7c478bd9Sstevel@tonic-gate 		(void *)&((struct sockaddr_in *)taddr->buf)->sin_addr);
2811*7c478bd9Sstevel@tonic-gate 
2812*7c478bd9Sstevel@tonic-gate 	netdir_free(taddr, ND_ADDR);
2813*7c478bd9Sstevel@tonic-gate 	return (ret);
2814*7c478bd9Sstevel@tonic-gate }
2815*7c478bd9Sstevel@tonic-gate 
2816*7c478bd9Sstevel@tonic-gate 
2817*7c478bd9Sstevel@tonic-gate int
2818*7c478bd9Sstevel@tonic-gate __inet_address_count(void *p)
2819*7c478bd9Sstevel@tonic-gate {
2820*7c478bd9Sstevel@tonic-gate 	struct ifinfo *lp = (struct ifinfo *)p;
2821*7c478bd9Sstevel@tonic-gate 
2822*7c478bd9Sstevel@tonic-gate 	if (lp != 0) {
2823*7c478bd9Sstevel@tonic-gate 		return (lp->count);
2824*7c478bd9Sstevel@tonic-gate 	} else {
2825*7c478bd9Sstevel@tonic-gate 		return (0);
2826*7c478bd9Sstevel@tonic-gate 	}
2827*7c478bd9Sstevel@tonic-gate }
2828*7c478bd9Sstevel@tonic-gate 
2829*7c478bd9Sstevel@tonic-gate uint32_t
2830*7c478bd9Sstevel@tonic-gate __inet_get_addr(void *p, int n)
2831*7c478bd9Sstevel@tonic-gate {
2832*7c478bd9Sstevel@tonic-gate 	struct ifinfo *localinfo = (struct ifinfo *)p;
2833*7c478bd9Sstevel@tonic-gate 
2834*7c478bd9Sstevel@tonic-gate 	if (localinfo == 0 || n >= localinfo->count || ifaf(n) != AF_INET)
2835*7c478bd9Sstevel@tonic-gate 		return (0);
2836*7c478bd9Sstevel@tonic-gate 
2837*7c478bd9Sstevel@tonic-gate 	return (ifaddr4(n).s_addr);
2838*7c478bd9Sstevel@tonic-gate }
2839*7c478bd9Sstevel@tonic-gate 
2840*7c478bd9Sstevel@tonic-gate uint32_t
2841*7c478bd9Sstevel@tonic-gate __inet_get_network(void *p, int n)
2842*7c478bd9Sstevel@tonic-gate {
2843*7c478bd9Sstevel@tonic-gate 	struct ifinfo *localinfo = (struct ifinfo *)p;
2844*7c478bd9Sstevel@tonic-gate 
2845*7c478bd9Sstevel@tonic-gate 	if (localinfo == 0 || n >= localinfo->count || ifaf(n) != AF_INET)
2846*7c478bd9Sstevel@tonic-gate 		return (0);
2847*7c478bd9Sstevel@tonic-gate 
2848*7c478bd9Sstevel@tonic-gate 	return (ifaddr4(n).s_addr & ifmask4(n).s_addr);
2849*7c478bd9Sstevel@tonic-gate }
2850*7c478bd9Sstevel@tonic-gate 
2851*7c478bd9Sstevel@tonic-gate char *
2852*7c478bd9Sstevel@tonic-gate __inet_get_uaddr(void *p, struct netconfig *nc, int n)
2853*7c478bd9Sstevel@tonic-gate {
2854*7c478bd9Sstevel@tonic-gate 	struct ifinfo *localinfo = (struct ifinfo *)p;
2855*7c478bd9Sstevel@tonic-gate 	char *uaddr;
2856*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in sin4;
2857*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 sin6;
2858*7c478bd9Sstevel@tonic-gate 	struct sockaddr *sin;
2859*7c478bd9Sstevel@tonic-gate 	struct netbuf nb;
2860*7c478bd9Sstevel@tonic-gate 
2861*7c478bd9Sstevel@tonic-gate 	if (localinfo == 0 || nc == 0 || n >= localinfo->count)
2862*7c478bd9Sstevel@tonic-gate 		return (0);
2863*7c478bd9Sstevel@tonic-gate 
2864*7c478bd9Sstevel@tonic-gate 	if (ifaf(n) == AF_INET6) {
2865*7c478bd9Sstevel@tonic-gate 		if (strcmp(NC_INET6, nc->nc_protofmly) != 0)
2866*7c478bd9Sstevel@tonic-gate 			return (0);
2867*7c478bd9Sstevel@tonic-gate 		memset(&sin6, 0, sizeof (sin6));
2868*7c478bd9Sstevel@tonic-gate 		sin6.sin6_family = AF_INET6;
2869*7c478bd9Sstevel@tonic-gate 		sin6.sin6_addr = ifaddr6(n);
2870*7c478bd9Sstevel@tonic-gate 		nb.buf = (char *)&sin6;
2871*7c478bd9Sstevel@tonic-gate 		nb.len = sizeof (sin6);
2872*7c478bd9Sstevel@tonic-gate 	} else {
2873*7c478bd9Sstevel@tonic-gate 		if (strcmp(NC_INET, nc->nc_protofmly) != 0)
2874*7c478bd9Sstevel@tonic-gate 			return (0);
2875*7c478bd9Sstevel@tonic-gate 		memset(&sin4, 0, sizeof (sin4));
2876*7c478bd9Sstevel@tonic-gate 		sin4.sin_family = AF_INET;
2877*7c478bd9Sstevel@tonic-gate 		sin4.sin_addr = ifaddr4(n);
2878*7c478bd9Sstevel@tonic-gate 		nb.buf = (char *)&sin4;
2879*7c478bd9Sstevel@tonic-gate 		nb.len = sizeof (sin4);
2880*7c478bd9Sstevel@tonic-gate 	}
2881*7c478bd9Sstevel@tonic-gate 
2882*7c478bd9Sstevel@tonic-gate 	nb.maxlen = nb.len;
2883*7c478bd9Sstevel@tonic-gate 
2884*7c478bd9Sstevel@tonic-gate 	uaddr = taddr2uaddr(nc, &nb);
2885*7c478bd9Sstevel@tonic-gate 	return (uaddr);
2886*7c478bd9Sstevel@tonic-gate }
2887*7c478bd9Sstevel@tonic-gate 
2888*7c478bd9Sstevel@tonic-gate char *
2889*7c478bd9Sstevel@tonic-gate __inet_get_networka(void *p, int n)
2890*7c478bd9Sstevel@tonic-gate {
2891*7c478bd9Sstevel@tonic-gate 	struct ifinfo	*localinfo = (struct ifinfo *)p;
2892*7c478bd9Sstevel@tonic-gate 
2893*7c478bd9Sstevel@tonic-gate 	if (localinfo == 0 || n >= localinfo->count)
2894*7c478bd9Sstevel@tonic-gate 		return (0);
2895*7c478bd9Sstevel@tonic-gate 
2896*7c478bd9Sstevel@tonic-gate 	if (ifaf(n) == AF_INET6) {
2897*7c478bd9Sstevel@tonic-gate 		char		buf[INET6_ADDRSTRLEN];
2898*7c478bd9Sstevel@tonic-gate 		struct in6_addr	in6;
2899*7c478bd9Sstevel@tonic-gate 		int		i;
2900*7c478bd9Sstevel@tonic-gate 
2901*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < sizeof (in6.s6_addr); i++) {
2902*7c478bd9Sstevel@tonic-gate 			in6.s6_addr[i] = ifaddr6(n).s6_addr[i] &
2903*7c478bd9Sstevel@tonic-gate 					ifmask6(n).s6_addr[i];
2904*7c478bd9Sstevel@tonic-gate 		}
2905*7c478bd9Sstevel@tonic-gate 		return (strdup(inet_ntop(AF_INET6, &in6, buf, sizeof (buf))));
2906*7c478bd9Sstevel@tonic-gate 	} else {
2907*7c478bd9Sstevel@tonic-gate 		struct in_addr	in4;
2908*7c478bd9Sstevel@tonic-gate 
2909*7c478bd9Sstevel@tonic-gate 		in4.s_addr = ifaddr4(n).s_addr & ifmask4(n).s_addr;
2910*7c478bd9Sstevel@tonic-gate 		return (strdup(inet_ntoa(in4)));
2911*7c478bd9Sstevel@tonic-gate 	}
2912*7c478bd9Sstevel@tonic-gate }
2913*7c478bd9Sstevel@tonic-gate 
2914*7c478bd9Sstevel@tonic-gate static int
2915*7c478bd9Sstevel@tonic-gate in_list(struct in_addr *addrs, int n, struct in_addr a)
2916*7c478bd9Sstevel@tonic-gate {
2917*7c478bd9Sstevel@tonic-gate 	int i;
2918*7c478bd9Sstevel@tonic-gate 
2919*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
2920*7c478bd9Sstevel@tonic-gate 		if (addrs[i].s_addr == a.s_addr)
2921*7c478bd9Sstevel@tonic-gate 			return (1);
2922*7c478bd9Sstevel@tonic-gate 	}
2923*7c478bd9Sstevel@tonic-gate 	return (0);
2924*7c478bd9Sstevel@tonic-gate }
2925*7c478bd9Sstevel@tonic-gate 
2926*7c478bd9Sstevel@tonic-gate static int
2927*7c478bd9Sstevel@tonic-gate getbroadcastnets(struct netconfig *tp, struct in_addr **addrs)
2928*7c478bd9Sstevel@tonic-gate {
2929*7c478bd9Sstevel@tonic-gate 	struct ifconf ifc;
2930*7c478bd9Sstevel@tonic-gate 	struct ifreq ifreq, *ifr;
2931*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
2932*7c478bd9Sstevel@tonic-gate 	struct in_addr a;
2933*7c478bd9Sstevel@tonic-gate 	int fd;
2934*7c478bd9Sstevel@tonic-gate 	int n, i, numifs;
2935*7c478bd9Sstevel@tonic-gate 	char *buf;
2936*7c478bd9Sstevel@tonic-gate 	int	use_loopback = 0;
2937*7c478bd9Sstevel@tonic-gate 
2938*7c478bd9Sstevel@tonic-gate 	_nderror = ND_SYSTEM;
2939*7c478bd9Sstevel@tonic-gate 	fd = open(tp->nc_device, O_RDONLY);
2940*7c478bd9Sstevel@tonic-gate 	if (fd < 0) {
2941*7c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
2942*7c478bd9Sstevel@tonic-gate 	    "broadcast: open to get interface configuration: %m");
2943*7c478bd9Sstevel@tonic-gate 		return (0);
2944*7c478bd9Sstevel@tonic-gate 	}
2945*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0)
2946*7c478bd9Sstevel@tonic-gate 		numifs = MAXIFS;
2947*7c478bd9Sstevel@tonic-gate 	buf = (char *)malloc(numifs * sizeof (struct ifreq));
2948*7c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
2949*7c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "broadcast: malloc failed: %m");
2950*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
2951*7c478bd9Sstevel@tonic-gate 		return (0);
2952*7c478bd9Sstevel@tonic-gate 	}
2953*7c478bd9Sstevel@tonic-gate 	*addrs = (struct in_addr *)malloc(numifs * sizeof (struct in_addr));
2954*7c478bd9Sstevel@tonic-gate 	if (*addrs == NULL) {
2955*7c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "broadcast: malloc failed: %m");
2956*7c478bd9Sstevel@tonic-gate 		free(buf);
2957*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
2958*7c478bd9Sstevel@tonic-gate 		return (0);
2959*7c478bd9Sstevel@tonic-gate 	}
2960*7c478bd9Sstevel@tonic-gate 	ifc.ifc_len = numifs * (int)sizeof (struct ifreq);
2961*7c478bd9Sstevel@tonic-gate 	ifc.ifc_buf = buf;
2962*7c478bd9Sstevel@tonic-gate 	/*
2963*7c478bd9Sstevel@tonic-gate 	 * Ideally, this ioctl should also tell me, how many bytes were
2964*7c478bd9Sstevel@tonic-gate 	 * finally allocated, but it doesnt.
2965*7c478bd9Sstevel@tonic-gate 	 */
2966*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) {
2967*7c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
2968*7c478bd9Sstevel@tonic-gate 	    "broadcast: ioctl (get interface configuration): %m");
2969*7c478bd9Sstevel@tonic-gate 		free(buf);
2970*7c478bd9Sstevel@tonic-gate 		free(*addrs);
2971*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
2972*7c478bd9Sstevel@tonic-gate 		return (0);
2973*7c478bd9Sstevel@tonic-gate 	}
2974*7c478bd9Sstevel@tonic-gate 
2975*7c478bd9Sstevel@tonic-gate retry:
2976*7c478bd9Sstevel@tonic-gate 	ifr = (struct ifreq *)buf;
2977*7c478bd9Sstevel@tonic-gate 	for (i = 0, n = ifc.ifc_len / (int)sizeof (struct ifreq);
2978*7c478bd9Sstevel@tonic-gate 		n > 0; n--, ifr++) {
2979*7c478bd9Sstevel@tonic-gate 		ifreq = *ifr;
2980*7c478bd9Sstevel@tonic-gate 		if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
2981*7c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
2982*7c478bd9Sstevel@tonic-gate 		    "broadcast: ioctl (get interface flags): %m");
2983*7c478bd9Sstevel@tonic-gate 			continue;
2984*7c478bd9Sstevel@tonic-gate 		}
2985*7c478bd9Sstevel@tonic-gate 		if (!(ifreq.ifr_flags & IFF_UP) ||
2986*7c478bd9Sstevel@tonic-gate 		    (ifr->ifr_addr.sa_family != AF_INET))
2987*7c478bd9Sstevel@tonic-gate 			continue;
2988*7c478bd9Sstevel@tonic-gate 		if (ifreq.ifr_flags & IFF_BROADCAST) {
2989*7c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&ifr->ifr_addr;
2990*7c478bd9Sstevel@tonic-gate 			if (ioctl(fd, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
2991*7c478bd9Sstevel@tonic-gate 				/* May not work with other implementation */
2992*7c478bd9Sstevel@tonic-gate 				a = _inet_makeaddr(
2993*7c478bd9Sstevel@tonic-gate 				    inet_netof(sin->sin_addr),
2994*7c478bd9Sstevel@tonic-gate 				    INADDR_ANY);
2995*7c478bd9Sstevel@tonic-gate 				if (!in_list(*addrs, i, a))
2996*7c478bd9Sstevel@tonic-gate 					(*addrs)[i++] = a;
2997*7c478bd9Sstevel@tonic-gate 			} else {
2998*7c478bd9Sstevel@tonic-gate 				a = ((struct sockaddr_in *)
2999*7c478bd9Sstevel@tonic-gate 				    &ifreq.ifr_addr)->sin_addr;
3000*7c478bd9Sstevel@tonic-gate 				if (!in_list(*addrs, i, a))
3001*7c478bd9Sstevel@tonic-gate 					(*addrs)[i++] = a;
3002*7c478bd9Sstevel@tonic-gate 			}
3003*7c478bd9Sstevel@tonic-gate 			continue;
3004*7c478bd9Sstevel@tonic-gate 		}
3005*7c478bd9Sstevel@tonic-gate 		if (use_loopback && (ifreq.ifr_flags & IFF_LOOPBACK)) {
3006*7c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&ifr->ifr_addr;
3007*7c478bd9Sstevel@tonic-gate 			a = sin->sin_addr;
3008*7c478bd9Sstevel@tonic-gate 			if (!in_list(*addrs, i, a))
3009*7c478bd9Sstevel@tonic-gate 				(*addrs)[i++] = a;
3010*7c478bd9Sstevel@tonic-gate 			continue;
3011*7c478bd9Sstevel@tonic-gate 		}
3012*7c478bd9Sstevel@tonic-gate 		if (ifreq.ifr_flags & IFF_POINTOPOINT) {
3013*7c478bd9Sstevel@tonic-gate 			if (ioctl(fd, SIOCGIFDSTADDR, (char *)&ifreq) < 0)
3014*7c478bd9Sstevel@tonic-gate 				continue;
3015*7c478bd9Sstevel@tonic-gate 			a = ((struct sockaddr_in *)
3016*7c478bd9Sstevel@tonic-gate 			    &ifreq.ifr_addr)->sin_addr;
3017*7c478bd9Sstevel@tonic-gate 			if (!in_list(*addrs, i, a))
3018*7c478bd9Sstevel@tonic-gate 				(*addrs)[i++] = a;
3019*7c478bd9Sstevel@tonic-gate 			continue;
3020*7c478bd9Sstevel@tonic-gate 		}
3021*7c478bd9Sstevel@tonic-gate 	}
3022*7c478bd9Sstevel@tonic-gate 	if (i == 0 && !use_loopback) {
3023*7c478bd9Sstevel@tonic-gate 		use_loopback = 1;
3024*7c478bd9Sstevel@tonic-gate 		goto retry;
3025*7c478bd9Sstevel@tonic-gate 	}
3026*7c478bd9Sstevel@tonic-gate 	free(buf);
3027*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
3028*7c478bd9Sstevel@tonic-gate 	if (i)
3029*7c478bd9Sstevel@tonic-gate 		_nderror = ND_OK;
3030*7c478bd9Sstevel@tonic-gate 	else
3031*7c478bd9Sstevel@tonic-gate 		free(*addrs);
3032*7c478bd9Sstevel@tonic-gate 	return (i);
3033*7c478bd9Sstevel@tonic-gate }
3034*7c478bd9Sstevel@tonic-gate 
3035*7c478bd9Sstevel@tonic-gate /*
3036*7c478bd9Sstevel@tonic-gate  * This is lifted straight from libsocket/inet/inet_mkaddr.c.
3037*7c478bd9Sstevel@tonic-gate  * Copied here to avoid our dependency on libsocket. More importantly,
3038*7c478bd9Sstevel@tonic-gate  * to make sure partially static apps that use libnsl, but not
3039*7c478bd9Sstevel@tonic-gate  * libsocket, don't get screwed up.
3040*7c478bd9Sstevel@tonic-gate  * If you understand the above paragraph, try to get rid of
3041*7c478bd9Sstevel@tonic-gate  * this copy of inet_makeaddr; if you don;t, leave it alone.
3042*7c478bd9Sstevel@tonic-gate  *
3043*7c478bd9Sstevel@tonic-gate  * Formulate an Internet address from network + host.  Used in
3044*7c478bd9Sstevel@tonic-gate  * building addresses stored in the ifnet structure.
3045*7c478bd9Sstevel@tonic-gate  */
3046*7c478bd9Sstevel@tonic-gate static struct in_addr
3047*7c478bd9Sstevel@tonic-gate _inet_makeaddr(in_addr_t net, in_addr_t host)
3048*7c478bd9Sstevel@tonic-gate {
3049*7c478bd9Sstevel@tonic-gate 	in_addr_t addr;
3050*7c478bd9Sstevel@tonic-gate 	struct in_addr inaddr;
3051*7c478bd9Sstevel@tonic-gate 
3052*7c478bd9Sstevel@tonic-gate 	if (net < 128)
3053*7c478bd9Sstevel@tonic-gate 		addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST);
3054*7c478bd9Sstevel@tonic-gate 	else if (net < 65536)
3055*7c478bd9Sstevel@tonic-gate 		addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST);
3056*7c478bd9Sstevel@tonic-gate 	else if (net < 16777216L)
3057*7c478bd9Sstevel@tonic-gate 		addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST);
3058*7c478bd9Sstevel@tonic-gate 	else
3059*7c478bd9Sstevel@tonic-gate 		addr = net | host;
3060*7c478bd9Sstevel@tonic-gate 	inaddr.s_addr = htonl(addr);
3061*7c478bd9Sstevel@tonic-gate 	return (inaddr);
3062*7c478bd9Sstevel@tonic-gate }
3063*7c478bd9Sstevel@tonic-gate 
3064*7c478bd9Sstevel@tonic-gate /*
3065*7c478bd9Sstevel@tonic-gate  * Routine to read the default configuration file and check if SORT_ADDRS
3066*7c478bd9Sstevel@tonic-gate  * is set to NO or FALSE. This routine is called by order_haddrlist_af()
3067*7c478bd9Sstevel@tonic-gate  * to determine if the addresses need to be sorted.
3068*7c478bd9Sstevel@tonic-gate  */
3069*7c478bd9Sstevel@tonic-gate static boolean_t
3070*7c478bd9Sstevel@tonic-gate _read_nsw_file(void)
3071*7c478bd9Sstevel@tonic-gate {
3072*7c478bd9Sstevel@tonic-gate 	char	defval[LINESIZE];
3073*7c478bd9Sstevel@tonic-gate 	__NSL_FILE *defl;
3074*7c478bd9Sstevel@tonic-gate 	boolean_t	nosort = B_FALSE;
3075*7c478bd9Sstevel@tonic-gate 
3076*7c478bd9Sstevel@tonic-gate 
3077*7c478bd9Sstevel@tonic-gate 	do {
3078*7c478bd9Sstevel@tonic-gate 		defl = __nsl_fopen(__NSW_DEFAULT_FILE, "r");
3079*7c478bd9Sstevel@tonic-gate 	} while ((defl == NULL) && (errno == EINTR));
3080*7c478bd9Sstevel@tonic-gate 
3081*7c478bd9Sstevel@tonic-gate 	if (defl == NULL)
3082*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
3083*7c478bd9Sstevel@tonic-gate 
3084*7c478bd9Sstevel@tonic-gate 	while (__nsl_fgets(defval, sizeof (defval), defl) != NULL) {
3085*7c478bd9Sstevel@tonic-gate 		if ((strncmp(DONT_SORT, defval, sizeof (DONT_SORT) - 1) == 0) ||
3086*7c478bd9Sstevel@tonic-gate 		    (strncmp(DONT_SORT2, defval,
3087*7c478bd9Sstevel@tonic-gate 			sizeof (DONT_SORT2) - 1) == 0)) {
3088*7c478bd9Sstevel@tonic-gate 			nosort = B_TRUE;
3089*7c478bd9Sstevel@tonic-gate 			break;
3090*7c478bd9Sstevel@tonic-gate 		}
3091*7c478bd9Sstevel@tonic-gate 	}
3092*7c478bd9Sstevel@tonic-gate 	__nsl_fclose(defl);
3093*7c478bd9Sstevel@tonic-gate 	return (nosort);
3094*7c478bd9Sstevel@tonic-gate }
3095