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