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