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