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