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