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