xref: /onnv-gate/usr/src/lib/libnsl/nss/netdir_inet.c (revision 7752:bfffde2d0b5b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51914Scasper  * Common Development and Distribution License (the "License").
61914Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21132Srobinson 
220Sstevel@tonic-gate /*
23*7752SMichen.Chang@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
251229Sraf  */
261229Sraf 
271229Sraf /*
280Sstevel@tonic-gate  * This is where we have chosen to combine every useful bit of code for
290Sstevel@tonic-gate  * all the Solaris frontends to lookup hosts, services, and netdir information
300Sstevel@tonic-gate  * for inet family (udp, tcp) transports. gethostbyYY(), getservbyYY(), and
310Sstevel@tonic-gate  * netdir_getbyYY() are all implemented on top of this code. Similarly,
320Sstevel@tonic-gate  * netdir_options, taddr2uaddr, and uaddr2taddr for inet transports also
330Sstevel@tonic-gate  * find a home here.
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * If the netconfig structure supplied has NO nametoaddr libs (i.e. a "-"
360Sstevel@tonic-gate  * in /etc/netconfig), this code calls the name service switch, and
370Sstevel@tonic-gate  * therefore, /etc/nsswitch.conf is effectively the only place that
380Sstevel@tonic-gate  * dictates hosts/serv lookup policy.
390Sstevel@tonic-gate  * If an administrator chooses to bypass the name service switch by
400Sstevel@tonic-gate  * specifying third party supplied nametoaddr libs in /etc/netconfig, this
410Sstevel@tonic-gate  * implementation does NOT call the name service switch, it merely loops
420Sstevel@tonic-gate  * through the nametoaddr libs. In this case, if this code was called
430Sstevel@tonic-gate  * from gethost/servbyYY() we marshal the inet specific struct into
440Sstevel@tonic-gate  * transport independent netbuf or hostserv, and unmarshal the resulting
450Sstevel@tonic-gate  * nd_addrlist or hostservlist back into hostent and servent, as the case
460Sstevel@tonic-gate  * may be.
470Sstevel@tonic-gate  *
480Sstevel@tonic-gate  * Goes without saying that most of the future bugs in gethost/servbyYY
490Sstevel@tonic-gate  * and netdir_getbyYY are lurking somewhere here.
500Sstevel@tonic-gate  */
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #include "mt.h"
530Sstevel@tonic-gate #include <ctype.h>
540Sstevel@tonic-gate #include <stdio.h>
550Sstevel@tonic-gate #include <stdlib.h>
560Sstevel@tonic-gate #include <string.h>
570Sstevel@tonic-gate #include <unistd.h>
580Sstevel@tonic-gate #include <stropts.h>
590Sstevel@tonic-gate #include <sys/types.h>
600Sstevel@tonic-gate #include <sys/byteorder.h>
610Sstevel@tonic-gate #include <sys/ioctl.h>
620Sstevel@tonic-gate #include <sys/param.h>
630Sstevel@tonic-gate #include <sys/time.h>
640Sstevel@tonic-gate #include <errno.h>
650Sstevel@tonic-gate #include <fcntl.h>
660Sstevel@tonic-gate #include <thread.h>
670Sstevel@tonic-gate #include <synch.h>
680Sstevel@tonic-gate #include <sys/utsname.h>
690Sstevel@tonic-gate #include <netdb.h>
700Sstevel@tonic-gate #include <netconfig.h>
710Sstevel@tonic-gate #include <netdir.h>
720Sstevel@tonic-gate #include <tiuser.h>
730Sstevel@tonic-gate #include <sys/socket.h>
740Sstevel@tonic-gate #include <sys/sockio.h>
750Sstevel@tonic-gate #include <netinet/in.h>
760Sstevel@tonic-gate #include <arpa/inet.h>
770Sstevel@tonic-gate #include <net/if.h>
780Sstevel@tonic-gate #include <inet/ip.h>
790Sstevel@tonic-gate #include <inet/ip6_asp.h>
800Sstevel@tonic-gate #include <sys/dlpi.h>
810Sstevel@tonic-gate #include <nss_dbdefs.h>
820Sstevel@tonic-gate #include <nss_netdir.h>
830Sstevel@tonic-gate #include <syslog.h>
840Sstevel@tonic-gate #include <nsswitch.h>
850Sstevel@tonic-gate #include "nss.h"
860Sstevel@tonic-gate 
870Sstevel@tonic-gate #define	MAXIFS 32
880Sstevel@tonic-gate #define	UDPDEV	"/dev/udp"
890Sstevel@tonic-gate #define	UDP6DEV	"/dev/udp6"
900Sstevel@tonic-gate 
910Sstevel@tonic-gate #define	DOOR_GETHOSTBYNAME_R	_switch_gethostbyname_r
920Sstevel@tonic-gate #define	DOOR_GETHOSTBYADDR_R	_switch_gethostbyaddr_r
930Sstevel@tonic-gate #define	DOOR_GETIPNODEBYNAME_R	_switch_getipnodebyname_r
940Sstevel@tonic-gate #define	DOOR_GETIPNODEBYADDR_R	_switch_getipnodebyaddr_r
950Sstevel@tonic-gate 
960Sstevel@tonic-gate #define	DONT_SORT	"SORT_ADDRS=NO"
970Sstevel@tonic-gate #define	DONT_SORT2	"SORT_ADDRS=FALSE"
980Sstevel@tonic-gate #define	LINESIZE	100
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate /*
1010Sstevel@tonic-gate  * constant values of addresses for HOST_SELF_BIND, HOST_SELF_CONNECT
1020Sstevel@tonic-gate  * and localhost.
1030Sstevel@tonic-gate  *
1040Sstevel@tonic-gate  * The following variables are static to the extent that they should
1050Sstevel@tonic-gate  * not be visible outside of this file.
1060Sstevel@tonic-gate  */
1070Sstevel@tonic-gate static char *localaddr[] = {"\000\000\000\000", NULL};
1080Sstevel@tonic-gate static char *connectaddr[] = {"\177\000\000\001", NULL};
1090Sstevel@tonic-gate static char *localaddr6[] =
1100Sstevel@tonic-gate {"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", NULL};
1110Sstevel@tonic-gate static char *connectaddr6[] =
1120Sstevel@tonic-gate {"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001", NULL};
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate /* IPv4 nd_addrlist */
1150Sstevel@tonic-gate static mutex_t	nd_addr_lock = DEFAULTMUTEX;
1160Sstevel@tonic-gate static struct sockaddr_in sa_con;
1170Sstevel@tonic-gate static struct netbuf nd_conbuf = {sizeof (sa_con),\
1180Sstevel@tonic-gate     sizeof (sa_con), (char *)&sa_con};
1190Sstevel@tonic-gate static struct nd_addrlist nd_conaddrlist = {1, &nd_conbuf};
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /* IPv6 nd_addrlist */
1220Sstevel@tonic-gate static mutex_t	nd6_addr_lock = DEFAULTMUTEX;
1230Sstevel@tonic-gate static struct sockaddr_in6 sa6_con;
1240Sstevel@tonic-gate static struct netbuf nd6_conbuf = {sizeof (sa6_con),\
1250Sstevel@tonic-gate 	sizeof (sa6_con), (char *)&sa6_con};
1260Sstevel@tonic-gate static struct nd_addrlist nd6_conaddrlist = {1, &nd6_conbuf};
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate #define	LOCALHOST "localhost"
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate struct servent *_switch_getservbyname_r(const char *, const char *,
1310Sstevel@tonic-gate     struct servent *, char *, int);
1320Sstevel@tonic-gate struct servent *_switch_getservbyport_r(int, const char *, struct servent *,
1330Sstevel@tonic-gate     char *, int);
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate static int __herrno2netdir(int h_errnop);
1360Sstevel@tonic-gate static struct ifinfo *get_local_info(void);
1370Sstevel@tonic-gate static int getbroadcastnets(struct netconfig *, struct in_addr **);
1380Sstevel@tonic-gate static int hent2ndaddr(int, char **, int *, struct nd_addrlist **);
1390Sstevel@tonic-gate static int ndaddr2hent(int, const char *, struct nd_addrlist *,
1400Sstevel@tonic-gate     struct hostent *, char *, int);
1410Sstevel@tonic-gate static int hsents2ndhostservs(struct hostent *, struct servent *, ushort_t,
1420Sstevel@tonic-gate     struct nd_hostservlist **);
1430Sstevel@tonic-gate static int ndaddr2srent(const char *, const char *, ushort_t, struct servent *,
1440Sstevel@tonic-gate     char *, int);
1450Sstevel@tonic-gate static int ndhostserv2hent(struct netbuf *, struct nd_hostservlist *,
1460Sstevel@tonic-gate     struct hostent *, char *, int);
1470Sstevel@tonic-gate static int ndhostserv2srent(int, const char *, struct nd_hostservlist *,
1480Sstevel@tonic-gate     struct servent *, char *, int);
1490Sstevel@tonic-gate static int nd2herrno(int nerr);
1500Sstevel@tonic-gate static void order_haddrlist_inet(char **haddrlist, size_t addrcount);
1510Sstevel@tonic-gate static void order_haddrlist_inet6(char **haddrlist, size_t addrcount);
1520Sstevel@tonic-gate static int dstcmp(const void *, const void *);
1530Sstevel@tonic-gate static int nss_strioctl(int af, int cmd, void *ptr, int ilen);
1540Sstevel@tonic-gate static struct in_addr _inet_makeaddr(in_addr_t, in_addr_t);
1550Sstevel@tonic-gate static boolean_t _read_nsw_file(void);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate /*
1580Sstevel@tonic-gate  * Begin: PART I
1590Sstevel@tonic-gate  * Top Level Interfaces that gethost/serv/netdir funnel through.
1600Sstevel@tonic-gate  */
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate /*
1630Sstevel@tonic-gate  * gethost/servbyname always call this function; if they call
1640Sstevel@tonic-gate  * with nametoaddr libs in nconf, we call netdir_getbyname
1650Sstevel@tonic-gate  * implementation: __classic_netdir_getbyname, otherwise nsswitch.
1660Sstevel@tonic-gate  *
1670Sstevel@tonic-gate  * netdir_getbyname calls this only if nametoaddr libs are NOT
1680Sstevel@tonic-gate  * specified for inet transports; i.e. it's supposed to follow
1690Sstevel@tonic-gate  * the name service switch.
1700Sstevel@tonic-gate  */
1710Sstevel@tonic-gate int
_get_hostserv_inetnetdir_byname(struct netconfig * nconf,struct nss_netdirbyname_in * args,union nss_netdirbyname_out * res)1720Sstevel@tonic-gate _get_hostserv_inetnetdir_byname(struct netconfig *nconf,
1730Sstevel@tonic-gate     struct nss_netdirbyname_in *args, union nss_netdirbyname_out *res)
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	int	server_port;
1760Sstevel@tonic-gate 	int *servp = &server_port;
1770Sstevel@tonic-gate 	char	**haddrlist;
1780Sstevel@tonic-gate 	uint32_t dotnameaddr;
1790Sstevel@tonic-gate 	char	*dotnamelist[2];
1800Sstevel@tonic-gate 	struct in_addr	*inaddrs = NULL;
1810Sstevel@tonic-gate 	struct in6_addr	v6nameaddr;
1820Sstevel@tonic-gate 	char	**baddrlist = NULL;
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	if (nconf == NULL) {
1860Sstevel@tonic-gate 		_nderror = ND_BADARG;
1870Sstevel@tonic-gate 		return (ND_BADARG);
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	/*
1910Sstevel@tonic-gate 	 * 1. gethostbyname()/netdir_getbyname() special cases:
1920Sstevel@tonic-gate 	 */
1930Sstevel@tonic-gate 	switch (args->op_t) {
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 		case NSS_HOST:
1960Sstevel@tonic-gate 		/*
1970Sstevel@tonic-gate 		 * Worth the performance gain -- assuming a lot of inet apps
1980Sstevel@tonic-gate 		 * actively use "localhost".
1990Sstevel@tonic-gate 		 */
2000Sstevel@tonic-gate 		if (strcmp(args->arg.nss.host.name, LOCALHOST) == 0) {
2010Sstevel@tonic-gate 
202132Srobinson 			(void) mutex_lock(&nd_addr_lock);
2030Sstevel@tonic-gate 			IN_SET_LOOPBACK_ADDR(&sa_con);
2040Sstevel@tonic-gate 			_nderror = ndaddr2hent(AF_INET, args->arg.nss.host.name,
2050Sstevel@tonic-gate 			    &nd_conaddrlist, res->nss.host.hent,
2060Sstevel@tonic-gate 			    args->arg.nss.host.buf,
2070Sstevel@tonic-gate 			    args->arg.nss.host.buflen);
208132Srobinson 			(void) mutex_unlock(&nd_addr_lock);
2090Sstevel@tonic-gate 			if (_nderror != ND_OK)
2100Sstevel@tonic-gate 				*(res->nss.host.herrno_p) =
2110Sstevel@tonic-gate 				    nd2herrno(_nderror);
2120Sstevel@tonic-gate 			return (_nderror);
2130Sstevel@tonic-gate 		}
2140Sstevel@tonic-gate 		/*
2150Sstevel@tonic-gate 		 * If the caller passed in a dot separated IP notation to
2160Sstevel@tonic-gate 		 * gethostbyname, return that back as the address.
2170Sstevel@tonic-gate 		 * The nd_addr_lock mutex was added to be truely re-entrant.
2180Sstevel@tonic-gate 		 */
2191229Sraf 		if (inet_aton(args->arg.nss.host.name,
2200Sstevel@tonic-gate 		    (struct in_addr *)&dotnameaddr)) {
221132Srobinson 			(void) mutex_lock(&nd_addr_lock);
222132Srobinson 			(void) memset(&sa_con, 0, sizeof (sa_con));
2230Sstevel@tonic-gate 			sa_con.sin_family = AF_INET;
2240Sstevel@tonic-gate 			sa_con.sin_addr.s_addr = dotnameaddr;
2250Sstevel@tonic-gate 			_nderror = ndaddr2hent(AF_INET, args->arg.nss.host.name,
2260Sstevel@tonic-gate 			    &nd_conaddrlist, res->nss.host.hent,
2270Sstevel@tonic-gate 			    args->arg.nss.host.buf,
2280Sstevel@tonic-gate 			    args->arg.nss.host.buflen);
229132Srobinson 			(void) mutex_unlock(&nd_addr_lock);
2300Sstevel@tonic-gate 			if (_nderror != ND_OK)
2310Sstevel@tonic-gate 				*(res->nss.host.herrno_p) =
2320Sstevel@tonic-gate 				    nd2herrno(_nderror);
2330Sstevel@tonic-gate 			return (_nderror);
2340Sstevel@tonic-gate 		}
2350Sstevel@tonic-gate 		break;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 		case NSS_HOST6:
2380Sstevel@tonic-gate 		/*
2390Sstevel@tonic-gate 		 * Handle case of literal address string.
2400Sstevel@tonic-gate 		 */
2410Sstevel@tonic-gate 		if (strchr(args->arg.nss.host6.name, ':') != NULL &&
2420Sstevel@tonic-gate 		    (inet_pton(AF_INET6, args->arg.nss.host6.name,
2430Sstevel@tonic-gate 		    &v6nameaddr) != 0)) {
2440Sstevel@tonic-gate 			int	ret;
2450Sstevel@tonic-gate 
246132Srobinson 			(void) mutex_lock(&nd6_addr_lock);
247132Srobinson 			(void) memset(&sa6_con, 0, sizeof (sa6_con));
2480Sstevel@tonic-gate 			sa6_con.sin6_family = AF_INET6;
249132Srobinson 			(void) memcpy(&(sa6_con.sin6_addr.s6_addr),
2500Sstevel@tonic-gate 			    &v6nameaddr, sizeof (struct in6_addr));
2510Sstevel@tonic-gate 			ret = ndaddr2hent(AF_INET6,
2520Sstevel@tonic-gate 			    args->arg.nss.host6.name,
2530Sstevel@tonic-gate 			    &nd6_conaddrlist, res->nss.host.hent,
2540Sstevel@tonic-gate 			    args->arg.nss.host6.buf,
2550Sstevel@tonic-gate 			    args->arg.nss.host6.buflen);
256132Srobinson 			(void) mutex_unlock(&nd6_addr_lock);
2570Sstevel@tonic-gate 			if (ret != ND_OK)
2580Sstevel@tonic-gate 				*(res->nss.host.herrno_p) = nd2herrno(ret);
2590Sstevel@tonic-gate 			else
2600Sstevel@tonic-gate 				res->nss.host.hent->h_aliases = NULL;
2610Sstevel@tonic-gate 			return (ret);
2620Sstevel@tonic-gate 		}
2630Sstevel@tonic-gate 		break;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 		case NETDIR_BY:
2660Sstevel@tonic-gate 			if (args->arg.nd_hs == 0) {
2670Sstevel@tonic-gate 				_nderror = ND_BADARG;
2680Sstevel@tonic-gate 				return (ND_BADARG);
2690Sstevel@tonic-gate 			}
2700Sstevel@tonic-gate 			/*
2710Sstevel@tonic-gate 			 * If servname is NULL, return 0 as the port number
2720Sstevel@tonic-gate 			 * If servname is rpcbind, return 111 as the port number
2730Sstevel@tonic-gate 			 * If servname is a number, return it back as the port
2740Sstevel@tonic-gate 			 * number.
2750Sstevel@tonic-gate 			 */
2760Sstevel@tonic-gate 			if (args->arg.nd_hs->h_serv == 0) {
2770Sstevel@tonic-gate 				*servp = htons(0);
278*7752SMichen.Chang@Sun.COM 			} else if (strcmp(args->arg.nd_hs->h_serv,
279*7752SMichen.Chang@Sun.COM 			    "rpcbind") == 0) {
2800Sstevel@tonic-gate 				*servp = htons(111);
281*7752SMichen.Chang@Sun.COM 			} else if (strspn(args->arg.nd_hs->h_serv,
282*7752SMichen.Chang@Sun.COM 			    "0123456789") ==
283*7752SMichen.Chang@Sun.COM 			    strlen(args->arg.nd_hs->h_serv)) {
2840Sstevel@tonic-gate 				*servp = htons(atoi(args->arg.nd_hs->h_serv));
2850Sstevel@tonic-gate 			} else {
2860Sstevel@tonic-gate 				/* i.e. need to call a name service on this */
2870Sstevel@tonic-gate 				servp = NULL;
2880Sstevel@tonic-gate 			}
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 			/*
2910Sstevel@tonic-gate 			 * If the hostname is HOST_SELF_BIND, we return 0.0.0.0
2920Sstevel@tonic-gate 			 * so the  binding can be contacted through all
2930Sstevel@tonic-gate 			 * interfaces. If the hostname is HOST_SELF_CONNECT,
2940Sstevel@tonic-gate 			 * we return 127.0.0.1 so the address can be connected
2950Sstevel@tonic-gate 			 * to locally. If the hostname is HOST_ANY, we return
2960Sstevel@tonic-gate 			 * no addresses because IP doesn't know how to specify
2970Sstevel@tonic-gate 			 * a service without a host. And finally if we specify
2980Sstevel@tonic-gate 			 * HOST_BROADCAST then we ask a tli fd to tell us what
2990Sstevel@tonic-gate 			 * the broadcast addresses are for any udp
3000Sstevel@tonic-gate 			 * interfaces on this machine.
3010Sstevel@tonic-gate 			 */
3020Sstevel@tonic-gate 			if (args->arg.nd_hs->h_host == 0) {
3030Sstevel@tonic-gate 				_nderror = ND_NOHOST;
3040Sstevel@tonic-gate 				return (ND_NOHOST);
3050Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
3060Sstevel@tonic-gate 			    HOST_SELF_BIND) == 0)) {
3070Sstevel@tonic-gate 				haddrlist = localaddr;
3080Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
309*7752SMichen.Chang@Sun.COM 			    HOST_SELF_CONNECT) == 0)) {
3100Sstevel@tonic-gate 				haddrlist = connectaddr;
3110Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
312*7752SMichen.Chang@Sun.COM 			    LOCALHOST) == 0)) {
3130Sstevel@tonic-gate 				haddrlist = connectaddr;
3140Sstevel@tonic-gate 			} else if ((int)(dotnameaddr =
315*7752SMichen.Chang@Sun.COM 			    inet_addr(args->arg.nd_hs->h_host)) != -1) {
3160Sstevel@tonic-gate 				/*
3170Sstevel@tonic-gate 				 * If the caller passed in a dot separated IP
3180Sstevel@tonic-gate 				 * notation to netdir_getbyname, convert that
3190Sstevel@tonic-gate 				 * back into address.
3200Sstevel@tonic-gate 				 */
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 				dotnamelist[0] = (char *)&dotnameaddr;
3230Sstevel@tonic-gate 				dotnamelist[1] = NULL;
3240Sstevel@tonic-gate 				haddrlist = dotnamelist;
3250Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
326*7752SMichen.Chang@Sun.COM 			    HOST_BROADCAST) == 0)) {
3270Sstevel@tonic-gate 				/*
3280Sstevel@tonic-gate 				 * Now that inaddrs and baddrlist are
3290Sstevel@tonic-gate 				 * dynamically allocated, care must be
3300Sstevel@tonic-gate 				 * taken in freeing up the
3310Sstevel@tonic-gate 				 * memory at each 'return()' point.
3320Sstevel@tonic-gate 				 *
3330Sstevel@tonic-gate 				 * Early return protection (using
3340Sstevel@tonic-gate 				 * FREE_return()) is needed only in NETDIR_BY
3350Sstevel@tonic-gate 				 * cases because dynamic allocation is used
3360Sstevel@tonic-gate 				 * when args->op_t == NETDIR_BY.
3370Sstevel@tonic-gate 				 *
3380Sstevel@tonic-gate 				 * Early return protection is not needed in
3390Sstevel@tonic-gate 				 * haddrlist==0 conditionals because dynamic
3400Sstevel@tonic-gate 				 * allocation guarantees haddrlist!=0.
3410Sstevel@tonic-gate 				 *
3420Sstevel@tonic-gate 				 * Early return protection is not needed in most
3430Sstevel@tonic-gate 				 * servp!=0 conditionals because this is handled
3440Sstevel@tonic-gate 				 * (and returned) first.
3450Sstevel@tonic-gate 				 */
3460Sstevel@tonic-gate #define	FREE_return(ret) \
3470Sstevel@tonic-gate 				{ \
348*7752SMichen.Chang@Sun.COM 					if (inaddrs) \
349*7752SMichen.Chang@Sun.COM 						free(inaddrs); \
350*7752SMichen.Chang@Sun.COM 					if (baddrlist) \
351*7752SMichen.Chang@Sun.COM 						free(baddrlist); \
352*7752SMichen.Chang@Sun.COM 					_nderror = ret; \
353*7752SMichen.Chang@Sun.COM 					return (ret); \
3540Sstevel@tonic-gate 				}
3550Sstevel@tonic-gate 				int i, bnets;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 				bnets = getbroadcastnets(nconf, &inaddrs);
3580Sstevel@tonic-gate 				if (bnets == 0) {
3590Sstevel@tonic-gate 					_nderror = ND_NOHOST;
3600Sstevel@tonic-gate 					return (ND_NOHOST);
3610Sstevel@tonic-gate 				}
362132Srobinson 				baddrlist = malloc((bnets+1)*sizeof (char *));
3630Sstevel@tonic-gate 				if (baddrlist == NULL)
3640Sstevel@tonic-gate 					FREE_return(ND_NOMEM);
3650Sstevel@tonic-gate 				for (i = 0; i < bnets; i++)
3660Sstevel@tonic-gate 					baddrlist[i] = (char *)&inaddrs[i];
3670Sstevel@tonic-gate 				baddrlist[i] = NULL;
3680Sstevel@tonic-gate 				haddrlist = baddrlist;
3690Sstevel@tonic-gate 			} else {
3700Sstevel@tonic-gate 				/* i.e. need to call a name service on this */
3710Sstevel@tonic-gate 				haddrlist = 0;
3720Sstevel@tonic-gate 			}
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 			if (haddrlist && servp) {
3750Sstevel@tonic-gate 				int ret;
3760Sstevel@tonic-gate 				/*
3770Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
3780Sstevel@tonic-gate 				 * malloc's will be done, freed using
3790Sstevel@tonic-gate 				 * netdir_free.
3800Sstevel@tonic-gate 				 */
3810Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET, haddrlist, servp,
382*7752SMichen.Chang@Sun.COM 				    res->nd_alist);
383*7752SMichen.Chang@Sun.COM 				FREE_return(ret);
384*7752SMichen.Chang@Sun.COM 			}
3850Sstevel@tonic-gate 			break;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 		case NETDIR_BY6:
3890Sstevel@tonic-gate 			if (args->arg.nd_hs == 0) {
3900Sstevel@tonic-gate 				_nderror = ND_BADARG;
3910Sstevel@tonic-gate 				return (ND_BADARG);
3920Sstevel@tonic-gate 			}
3930Sstevel@tonic-gate 			/*
3940Sstevel@tonic-gate 			 * If servname is NULL, return 0 as the port number.
3950Sstevel@tonic-gate 			 * If servname is rpcbind, return 111 as the port number
3960Sstevel@tonic-gate 			 * If servname is a number, return it back as the port
3970Sstevel@tonic-gate 			 * number.
3980Sstevel@tonic-gate 			 */
3990Sstevel@tonic-gate 			if (args->arg.nd_hs->h_serv == 0) {
4000Sstevel@tonic-gate 				*servp = htons(0);
4010Sstevel@tonic-gate 			} else if (strcmp(args->arg.nd_hs->h_serv,
402*7752SMichen.Chang@Sun.COM 			    "rpcbind") == 0) {
4030Sstevel@tonic-gate 				*servp = htons(111);
4040Sstevel@tonic-gate 			} else if (strspn(args->arg.nd_hs->h_serv, "0123456789")
405*7752SMichen.Chang@Sun.COM 			    == strlen(args->arg.nd_hs->h_serv)) {
4060Sstevel@tonic-gate 				*servp = htons(atoi(args->arg.nd_hs->h_serv));
4070Sstevel@tonic-gate 			} else {
4080Sstevel@tonic-gate 				/* i.e. need to call a name service on this */
4090Sstevel@tonic-gate 				servp = NULL;
4100Sstevel@tonic-gate 			}
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 			/*
4130Sstevel@tonic-gate 			 * If the hostname is HOST_SELF_BIND, we return ipv6
4140Sstevel@tonic-gate 			 * localaddress so the binding can be contacted through
4150Sstevel@tonic-gate 			 * all interfaces.
4160Sstevel@tonic-gate 			 * If the hostname is HOST_SELF_CONNECT, we return
4170Sstevel@tonic-gate 			 * ipv6 loopback address so the address can be connected
4180Sstevel@tonic-gate 			 * to locally.
4190Sstevel@tonic-gate 			 * If the hostname is HOST_ANY, we return no addresses
4200Sstevel@tonic-gate 			 * because IP doesn't know how to specify a service
4210Sstevel@tonic-gate 			 * without a host.
4220Sstevel@tonic-gate 			 * And finally if we specify HOST_BROADCAST then we
4230Sstevel@tonic-gate 			 * disallow since IPV6 does not have any
4240Sstevel@tonic-gate 			 * broadcast concept.
4250Sstevel@tonic-gate 			 */
4260Sstevel@tonic-gate 			if (args->arg.nd_hs->h_host == 0) {
4270Sstevel@tonic-gate 				return (ND_NOHOST);
4280Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
429*7752SMichen.Chang@Sun.COM 			    HOST_SELF_BIND) == 0)) {
4300Sstevel@tonic-gate 				haddrlist = localaddr6;
4310Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
432*7752SMichen.Chang@Sun.COM 			    HOST_SELF_CONNECT) == 0)) {
4330Sstevel@tonic-gate 				haddrlist = connectaddr6;
4340Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
435*7752SMichen.Chang@Sun.COM 			    LOCALHOST) == 0)) {
4360Sstevel@tonic-gate 				haddrlist = connectaddr6;
4370Sstevel@tonic-gate 			} else if (strchr(args->arg.nd_hs->h_host, ':')
438*7752SMichen.Chang@Sun.COM 			    != NULL) {
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 			/*
4410Sstevel@tonic-gate 			 * If the caller passed in a dot separated IP notation
4420Sstevel@tonic-gate 			 * to netdir_getbyname, convert that back into address.
4430Sstevel@tonic-gate 			 */
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 				if ((inet_pton(AF_INET6,
446*7752SMichen.Chang@Sun.COM 				    args->arg.nd_hs->h_host,
447*7752SMichen.Chang@Sun.COM 				    &v6nameaddr)) != 0) {
4480Sstevel@tonic-gate 					dotnamelist[0] = (char *)&v6nameaddr;
4490Sstevel@tonic-gate 					dotnamelist[1] = NULL;
4500Sstevel@tonic-gate 					haddrlist = dotnamelist;
4510Sstevel@tonic-gate 				}
4520Sstevel@tonic-gate 				else
4530Sstevel@tonic-gate 					/* not sure what to return */
4540Sstevel@tonic-gate 					return (ND_NOHOST);
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
457*7752SMichen.Chang@Sun.COM 			    HOST_BROADCAST) == 0)) {
4580Sstevel@tonic-gate 				/*
4590Sstevel@tonic-gate 				 * Don't support broadcast in
4600Sstevel@tonic-gate 				 * IPV6
4610Sstevel@tonic-gate 				 */
4620Sstevel@tonic-gate 				return (ND_NOHOST);
4630Sstevel@tonic-gate 			} else {
4640Sstevel@tonic-gate 				/* i.e. need to call a name service on this */
4650Sstevel@tonic-gate 				haddrlist = 0;
4660Sstevel@tonic-gate 			}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 			if (haddrlist && servp) {
4690Sstevel@tonic-gate 				int ret;
4700Sstevel@tonic-gate 				/*
4710Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
4720Sstevel@tonic-gate 				 * malloc's will be done, freed
4730Sstevel@tonic-gate 				 * using netdir_free.
4740Sstevel@tonic-gate 				 */
4750Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET6, haddrlist,
4760Sstevel@tonic-gate 				    servp, res->nd_alist);
477*7752SMichen.Chang@Sun.COM 				FREE_return(ret);
478*7752SMichen.Chang@Sun.COM 			}
4790Sstevel@tonic-gate 			break;
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	}
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	/*
4850Sstevel@tonic-gate 	 * 2. Most common scenario. This is the way we ship /etc/netconfig.
4860Sstevel@tonic-gate 	 *    Emphasis on improving performance in the "if" part.
4870Sstevel@tonic-gate 	 */
4880Sstevel@tonic-gate 	if (nconf->nc_nlookups == 0) {
4890Sstevel@tonic-gate 		struct hostent	*he = NULL, *tmphe;
4900Sstevel@tonic-gate 		struct servent	*se;
4910Sstevel@tonic-gate 		int	ret;
4920Sstevel@tonic-gate 		nss_XbyY_buf_t	*ndbuf4switch = 0;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	switch (args->op_t) {
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 		case NSS_HOST:
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 		he = DOOR_GETHOSTBYNAME_R(args->arg.nss.host.name,
4990Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
5000Sstevel@tonic-gate 		    args->arg.nss.host.buflen,
5010Sstevel@tonic-gate 		    res->nss.host.herrno_p);
5020Sstevel@tonic-gate 		if (he == NULL)
5030Sstevel@tonic-gate 			return (_nderror = ND_NOHOST);
5040Sstevel@tonic-gate 		return (_nderror = ND_OK);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 		case NSS_HOST6:
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 		he = DOOR_GETIPNODEBYNAME_R(args->arg.nss.host6.name,
5090Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
5100Sstevel@tonic-gate 		    args->arg.nss.host6.buflen,
5110Sstevel@tonic-gate 		    args->arg.nss.host6.af_family,
5120Sstevel@tonic-gate 		    args->arg.nss.host6.flags,
5130Sstevel@tonic-gate 		    res->nss.host.herrno_p);
5140Sstevel@tonic-gate 
515132Srobinson 		if (he == NULL)
5160Sstevel@tonic-gate 			return (_nderror = ND_NOHOST);
5170Sstevel@tonic-gate 		return (_nderror = ND_OK);
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 		case NSS_SERV:
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 		se = _switch_getservbyname_r(args->arg.nss.serv.name,
5220Sstevel@tonic-gate 		    args->arg.nss.serv.proto,
5230Sstevel@tonic-gate 		    res->nss.serv, args->arg.nss.serv.buf,
5240Sstevel@tonic-gate 		    args->arg.nss.serv.buflen);
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 		_nderror = ND_OK;
5270Sstevel@tonic-gate 		if (se == 0)
5280Sstevel@tonic-gate 			_nderror = ND_NOSERV;
5290Sstevel@tonic-gate 		return (_nderror);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 		case NETDIR_BY:
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 		if (servp == 0) {
534*7752SMichen.Chang@Sun.COM 			char	*proto = (strcmp(nconf->nc_proto,
535*7752SMichen.Chang@Sun.COM 			    NC_TCP) == 0) ? NC_TCP : NC_UDP;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 			/*
5380Sstevel@tonic-gate 			 * We go through all this for just one port number,
5390Sstevel@tonic-gate 			 * which is most often constant. How about linking in
5400Sstevel@tonic-gate 			 * an indexed database of well-known ports in the name
5410Sstevel@tonic-gate 			 * of performance ?
5420Sstevel@tonic-gate 			 */
543132Srobinson 			ndbuf4switch = _nss_XbyY_buf_alloc(
544*7752SMichen.Chang@Sun.COM 			    sizeof (struct servent), NSS_BUFLEN_SERVICES);
5450Sstevel@tonic-gate 			if (ndbuf4switch == 0)
5460Sstevel@tonic-gate 				FREE_return(ND_NOMEM);
5470Sstevel@tonic-gate 			se = _switch_getservbyname_r(args->arg.nd_hs->h_serv,
548*7752SMichen.Chang@Sun.COM 			    proto, ndbuf4switch->result,
549*7752SMichen.Chang@Sun.COM 			    ndbuf4switch->buffer, ndbuf4switch->buflen);
5500Sstevel@tonic-gate 			if (!se) {
5510Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4switch);
552*7752SMichen.Chang@Sun.COM 				FREE_return(ND_NOSERV);
5530Sstevel@tonic-gate 			}
5540Sstevel@tonic-gate 			server_port = se->s_port;
5550Sstevel@tonic-gate 			NSS_XbyY_FREE(&ndbuf4switch);
5560Sstevel@tonic-gate 		}
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 		if (haddrlist == 0) {
5590Sstevel@tonic-gate 			int	h_errnop = 0;
5600Sstevel@tonic-gate 
561132Srobinson 			ndbuf4switch = _nss_XbyY_buf_alloc(
562*7752SMichen.Chang@Sun.COM 			    sizeof (struct hostent),
563*7752SMichen.Chang@Sun.COM 			    NSS_BUFLEN_HOSTS);
5640Sstevel@tonic-gate 			if (ndbuf4switch == 0) {
5650Sstevel@tonic-gate 				_nderror = ND_NOMEM;
5660Sstevel@tonic-gate 				return (ND_NOMEM);
5670Sstevel@tonic-gate 			}
5680Sstevel@tonic-gate 			/*
5690Sstevel@tonic-gate 			 * Search the ipnodes (v6) path first,
5700Sstevel@tonic-gate 			 * search will return the v4 addresses
5710Sstevel@tonic-gate 			 * as v4mapped addresses.
5720Sstevel@tonic-gate 			 */
5730Sstevel@tonic-gate 			if ((tmphe = DOOR_GETIPNODEBYNAME_R(
5740Sstevel@tonic-gate 			    args->arg.nd_hs->h_host,
5750Sstevel@tonic-gate 			    ndbuf4switch->result, ndbuf4switch->buffer,
5760Sstevel@tonic-gate 			    ndbuf4switch->buflen, args->arg.nss.host6.af_family,
5770Sstevel@tonic-gate 			    args->arg.nss.host6.flags, &h_errnop)) != NULL)
5780Sstevel@tonic-gate 				he = __mappedtov4(tmphe, &h_errnop);
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 			if (he == NULL) {
5810Sstevel@tonic-gate 				/* Failover case, try hosts db for v4 address */
5820Sstevel@tonic-gate 				he = DOOR_GETHOSTBYNAME_R(
583*7752SMichen.Chang@Sun.COM 				    args->arg.nd_hs->h_host,
584*7752SMichen.Chang@Sun.COM 				    ndbuf4switch->result, ndbuf4switch->buffer,
585*7752SMichen.Chang@Sun.COM 				    ndbuf4switch->buflen, &h_errnop);
5860Sstevel@tonic-gate 				if (he == NULL) {
5870Sstevel@tonic-gate 					NSS_XbyY_FREE(&ndbuf4switch);
5880Sstevel@tonic-gate 					_nderror = h_errnop ?
5890Sstevel@tonic-gate 					    __herrno2netdir(h_errnop) :
5900Sstevel@tonic-gate 					    ND_NOHOST;
5910Sstevel@tonic-gate 					return (_nderror);
5920Sstevel@tonic-gate 				}
5930Sstevel@tonic-gate 				/*
5940Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
5950Sstevel@tonic-gate 				 * malloc's will be done, freed using
5960Sstevel@tonic-gate 				 * netdir_free.
5970Sstevel@tonic-gate 				 */
5980Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET, he->h_addr_list,
599*7752SMichen.Chang@Sun.COM 				    &server_port, res->nd_alist);
6000Sstevel@tonic-gate 			} else {
6010Sstevel@tonic-gate 				/*
6020Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
6030Sstevel@tonic-gate 				 * malloc's will be done, freed using
6040Sstevel@tonic-gate 				 * netdir_free.
6050Sstevel@tonic-gate 				 */
6060Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET, he->h_addr_list,
607*7752SMichen.Chang@Sun.COM 				    &server_port, res->nd_alist);
6080Sstevel@tonic-gate 				freehostent(he);
6090Sstevel@tonic-gate 			}
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 			_nderror = ret;
6120Sstevel@tonic-gate 			NSS_XbyY_FREE(&ndbuf4switch);
6130Sstevel@tonic-gate 			return (ret);
6140Sstevel@tonic-gate 		} else {
6150Sstevel@tonic-gate 			int ret;
6160Sstevel@tonic-gate 			/*
6170Sstevel@tonic-gate 			 * Convert h_addr_list into nd_addrlist.
6180Sstevel@tonic-gate 			 * malloc's will be done, freed using netdir_free.
6190Sstevel@tonic-gate 			 */
6200Sstevel@tonic-gate 			ret = hent2ndaddr(AF_INET, haddrlist,
621*7752SMichen.Chang@Sun.COM 			    &server_port, res->nd_alist);
622*7752SMichen.Chang@Sun.COM 			FREE_return(ret);
6230Sstevel@tonic-gate 		}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 		case NETDIR_BY6:
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 			if (servp == 0) {
629*7752SMichen.Chang@Sun.COM 				char	*proto = (strcmp(nconf->nc_proto,
630*7752SMichen.Chang@Sun.COM 				    NC_TCP) == 0) ? NC_TCP : NC_UDP;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 				/*
6330Sstevel@tonic-gate 				 * We go through all this for just
6340Sstevel@tonic-gate 				 * one port number,
6350Sstevel@tonic-gate 				 * which is most often constant.
6360Sstevel@tonic-gate 				 * How about linking in
6370Sstevel@tonic-gate 				 * an indexed database of well-known
6380Sstevel@tonic-gate 				 * ports in the name
6390Sstevel@tonic-gate 				 * of performance ?
6400Sstevel@tonic-gate 				 */
641132Srobinson 				ndbuf4switch = _nss_XbyY_buf_alloc(
642*7752SMichen.Chang@Sun.COM 				    sizeof (struct servent),
643*7752SMichen.Chang@Sun.COM 				    NSS_BUFLEN_SERVICES);
6440Sstevel@tonic-gate 				if (ndbuf4switch == 0)
6450Sstevel@tonic-gate 					FREE_return(ND_NOMEM);
6460Sstevel@tonic-gate 				se = _switch_getservbyname_r(
647*7752SMichen.Chang@Sun.COM 				    args->arg.nd_hs->h_serv,
6480Sstevel@tonic-gate 				    proto, ndbuf4switch->result,
6490Sstevel@tonic-gate 				    ndbuf4switch->buffer, ndbuf4switch->buflen);
6500Sstevel@tonic-gate 				if (!se) {
6510Sstevel@tonic-gate 					NSS_XbyY_FREE(&ndbuf4switch);
652*7752SMichen.Chang@Sun.COM 					FREE_return(ND_NOSERV);
6530Sstevel@tonic-gate 				}
6540Sstevel@tonic-gate 				server_port = se->s_port;
6550Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4switch);
6560Sstevel@tonic-gate 			}
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 			if (haddrlist == 0) {
6590Sstevel@tonic-gate 				int	h_errnop = 0;
6600Sstevel@tonic-gate 
661132Srobinson 				ndbuf4switch = _nss_XbyY_buf_alloc(
662*7752SMichen.Chang@Sun.COM 				    sizeof (struct hostent),
663*7752SMichen.Chang@Sun.COM 				    NSS_BUFLEN_HOSTS);
6640Sstevel@tonic-gate 				if (ndbuf4switch == 0) {
6650Sstevel@tonic-gate 					_nderror = ND_NOMEM;
6660Sstevel@tonic-gate 					return (ND_NOMEM);
6670Sstevel@tonic-gate 				}
6680Sstevel@tonic-gate 				he = DOOR_GETIPNODEBYNAME_R(
6690Sstevel@tonic-gate 				    args->arg.nd_hs->h_host,
6700Sstevel@tonic-gate 				    ndbuf4switch->result, ndbuf4switch->buffer,
6710Sstevel@tonic-gate 				    ndbuf4switch->buflen,
6720Sstevel@tonic-gate 				    args->arg.nss.host6.af_family,
6730Sstevel@tonic-gate 				    args->arg.nss.host6.flags, &h_errnop);
6740Sstevel@tonic-gate 				if (he == NULL) {
6750Sstevel@tonic-gate 					NSS_XbyY_FREE(&ndbuf4switch);
6760Sstevel@tonic-gate 					_nderror = h_errnop ?
6770Sstevel@tonic-gate 					    __herrno2netdir(h_errnop) :
6780Sstevel@tonic-gate 					    ND_NOHOST;
6790Sstevel@tonic-gate 					return (_nderror);
6800Sstevel@tonic-gate 				}
6810Sstevel@tonic-gate 				/*
6820Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
6830Sstevel@tonic-gate 				 * malloc's will be done,
6840Sstevel@tonic-gate 				 * freed using netdir_free.
6850Sstevel@tonic-gate 				 */
6860Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET6,
687*7752SMichen.Chang@Sun.COM 				    ((struct hostent *)
688*7752SMichen.Chang@Sun.COM 				    (ndbuf4switch->result))->h_addr_list,
6890Sstevel@tonic-gate 				    &server_port, res->nd_alist);
6900Sstevel@tonic-gate 				_nderror = ret;
6910Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4switch);
6920Sstevel@tonic-gate 				return (ret);
6930Sstevel@tonic-gate 			} else {
6940Sstevel@tonic-gate 				int ret;
6950Sstevel@tonic-gate 				/*
6960Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
6970Sstevel@tonic-gate 				 * malloc's will be done,
6980Sstevel@tonic-gate 				 * freed using netdir_free.
6990Sstevel@tonic-gate 				 */
7000Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET6, haddrlist,
701*7752SMichen.Chang@Sun.COM 				    &server_port, res->nd_alist);
702*7752SMichen.Chang@Sun.COM 				FREE_return(ret);
7030Sstevel@tonic-gate 			}
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 		default:
706*7752SMichen.Chang@Sun.COM 			_nderror = ND_BADARG;
707*7752SMichen.Chang@Sun.COM 			return (ND_BADARG); /* should never happen */
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	} else {
7110Sstevel@tonic-gate 		/* haddrlist is no longer used, so clean up */
7120Sstevel@tonic-gate 		if (inaddrs)
7130Sstevel@tonic-gate 			free(inaddrs);
7140Sstevel@tonic-gate 		if (baddrlist)
7150Sstevel@tonic-gate 			free(baddrlist);
7160Sstevel@tonic-gate 	}
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	/*
7190Sstevel@tonic-gate 	 * 3. We come this far only if nametoaddr libs are specified for
7200Sstevel@tonic-gate 	 *    inet transports and we are called by gethost/servbyname only.
7210Sstevel@tonic-gate 	 */
7220Sstevel@tonic-gate 	switch (args->op_t) {
7230Sstevel@tonic-gate 		struct	nd_hostserv service;
7240Sstevel@tonic-gate 		struct	nd_addrlist *addrs;
7250Sstevel@tonic-gate 		int ret;
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 		case NSS_HOST:
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 		service.h_host = (char *)args->arg.nss.host.name;
7300Sstevel@tonic-gate 		service.h_serv = NULL;
7310Sstevel@tonic-gate 		if ((_nderror = __classic_netdir_getbyname(nconf,
732*7752SMichen.Chang@Sun.COM 		    &service, &addrs)) != ND_OK) {
7330Sstevel@tonic-gate 			*(res->nss.host.herrno_p) = nd2herrno(_nderror);
7340Sstevel@tonic-gate 			return (_nderror);
7350Sstevel@tonic-gate 		}
7360Sstevel@tonic-gate 		/*
7370Sstevel@tonic-gate 		 * convert addresses back into sockaddr for gethostbyname.
7380Sstevel@tonic-gate 		 */
7390Sstevel@tonic-gate 		ret = ndaddr2hent(AF_INET, service.h_host, addrs,
7400Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
7410Sstevel@tonic-gate 		    args->arg.nss.host.buflen);
7420Sstevel@tonic-gate 		if (ret != ND_OK)
7430Sstevel@tonic-gate 			*(res->nss.host.herrno_p) = nd2herrno(ret);
7440Sstevel@tonic-gate 		netdir_free((char *)addrs, ND_ADDRLIST);
7450Sstevel@tonic-gate 		_nderror = ret;
7460Sstevel@tonic-gate 		return (ret);
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 		case NSS_SERV:
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 		if (args->arg.nss.serv.proto == NULL) {
7510Sstevel@tonic-gate 			/*
7520Sstevel@tonic-gate 			 * A similar HACK showed up in Solaris 2.3.
7530Sstevel@tonic-gate 			 * The caller wild-carded proto -- i.e. will
7540Sstevel@tonic-gate 			 * accept a match using tcp or udp for the port
7550Sstevel@tonic-gate 			 * number. Since we have no hope of getting
7560Sstevel@tonic-gate 			 * directly to a name service switch backend
7570Sstevel@tonic-gate 			 * from here that understands this semantics,
7580Sstevel@tonic-gate 			 * we try calling the netdir interfaces first
7590Sstevel@tonic-gate 			 * with "tcp" and then "udp".
7600Sstevel@tonic-gate 			 */
7610Sstevel@tonic-gate 			args->arg.nss.serv.proto = "tcp";
7620Sstevel@tonic-gate 			_nderror = _get_hostserv_inetnetdir_byname(nconf, args,
7630Sstevel@tonic-gate 			    res);
7640Sstevel@tonic-gate 			if (_nderror != ND_OK) {
7650Sstevel@tonic-gate 				args->arg.nss.serv.proto = "udp";
7660Sstevel@tonic-gate 				_nderror =
7670Sstevel@tonic-gate 				    _get_hostserv_inetnetdir_byname(nconf,
7680Sstevel@tonic-gate 				    args, res);
7690Sstevel@tonic-gate 			}
7700Sstevel@tonic-gate 			return (_nderror);
7710Sstevel@tonic-gate 		}
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 		/*
7740Sstevel@tonic-gate 		 * Third-parties should optimize their nametoaddr
7750Sstevel@tonic-gate 		 * libraries for the HOST_SELF case.
7760Sstevel@tonic-gate 		 */
7770Sstevel@tonic-gate 		service.h_host = HOST_SELF;
7780Sstevel@tonic-gate 		service.h_serv = (char *)args->arg.nss.serv.name;
7790Sstevel@tonic-gate 		if ((_nderror = __classic_netdir_getbyname(nconf,
780*7752SMichen.Chang@Sun.COM 		    &service, &addrs)) != ND_OK) {
7810Sstevel@tonic-gate 			return (_nderror);
7820Sstevel@tonic-gate 		}
7830Sstevel@tonic-gate 		/*
7840Sstevel@tonic-gate 		 * convert addresses back into servent for getservbyname.
7850Sstevel@tonic-gate 		 */
7860Sstevel@tonic-gate 		_nderror = ndaddr2srent(service.h_serv,
7870Sstevel@tonic-gate 		    args->arg.nss.serv.proto,
788132Srobinson 		    /* LINTED pointer cast */
7890Sstevel@tonic-gate 		    ((struct sockaddr_in *)addrs->n_addrs->buf)->sin_port,
7900Sstevel@tonic-gate 		    res->nss.serv,
7910Sstevel@tonic-gate 		    args->arg.nss.serv.buf, args->arg.nss.serv.buflen);
7920Sstevel@tonic-gate 		netdir_free((char *)addrs, ND_ADDRLIST);
7930Sstevel@tonic-gate 		return (_nderror);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 		default:
7960Sstevel@tonic-gate 		_nderror = ND_BADARG;
7970Sstevel@tonic-gate 		return (ND_BADARG); /* should never happen */
7980Sstevel@tonic-gate 	}
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate /*
8020Sstevel@tonic-gate  * gethostbyaddr/servbyport always call this function; if they call
8030Sstevel@tonic-gate  * with nametoaddr libs in nconf, we call netdir_getbyaddr
8040Sstevel@tonic-gate  * implementation __classic_netdir_getbyaddr, otherwise nsswitch.
8050Sstevel@tonic-gate  *
8060Sstevel@tonic-gate  * netdir_getbyaddr calls this only if nametoaddr libs are NOT
8070Sstevel@tonic-gate  * specified for inet transports; i.e. it's supposed to follow
8080Sstevel@tonic-gate  * the name service switch.
8090Sstevel@tonic-gate  */
8100Sstevel@tonic-gate int
_get_hostserv_inetnetdir_byaddr(struct netconfig * nconf,struct nss_netdirbyaddr_in * args,union nss_netdirbyaddr_out * res)8110Sstevel@tonic-gate _get_hostserv_inetnetdir_byaddr(struct netconfig *nconf,
8120Sstevel@tonic-gate     struct nss_netdirbyaddr_in *args, union nss_netdirbyaddr_out *res)
8130Sstevel@tonic-gate {
8140Sstevel@tonic-gate 	if (nconf == 0) {
8150Sstevel@tonic-gate 		_nderror = ND_BADARG;
8160Sstevel@tonic-gate 		return (_nderror);
8170Sstevel@tonic-gate 	}
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	/*
8200Sstevel@tonic-gate 	 * 1. gethostbyaddr()/netdir_getbyaddr() special cases:
8210Sstevel@tonic-gate 	 */
8220Sstevel@tonic-gate 	switch (args->op_t) {
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 		case NSS_HOST:
8250Sstevel@tonic-gate 		/*
8260Sstevel@tonic-gate 		 * Worth the performance gain: assuming a lot of inet apps
8270Sstevel@tonic-gate 		 * actively use "127.0.0.1".
8280Sstevel@tonic-gate 		 */
829132Srobinson 		/* LINTED pointer cast */
8300Sstevel@tonic-gate 		if (*(uint32_t *)(args->arg.nss.host.addr) ==
831*7752SMichen.Chang@Sun.COM 		    htonl(INADDR_LOOPBACK)) {
832132Srobinson 			(void) mutex_lock(&nd_addr_lock);
8330Sstevel@tonic-gate 			IN_SET_LOOPBACK_ADDR(&sa_con);
8340Sstevel@tonic-gate 			_nderror = ndaddr2hent(AF_INET, LOCALHOST,
8350Sstevel@tonic-gate 			    &nd_conaddrlist, res->nss.host.hent,
8360Sstevel@tonic-gate 			    args->arg.nss.host.buf,
8370Sstevel@tonic-gate 			    args->arg.nss.host.buflen);
838132Srobinson 			(void) mutex_unlock(&nd_addr_lock);
8390Sstevel@tonic-gate 			if (_nderror != ND_OK)
8400Sstevel@tonic-gate 				*(res->nss.host.herrno_p) =
8410Sstevel@tonic-gate 				    nd2herrno(_nderror);
8420Sstevel@tonic-gate 			return (_nderror);
8430Sstevel@tonic-gate 		}
8440Sstevel@tonic-gate 		break;
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 		case NETDIR_BY:
8470Sstevel@tonic-gate 		case NETDIR_BY_NOSRV:
8480Sstevel@tonic-gate 		{
8490Sstevel@tonic-gate 			struct sockaddr_in *sin;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 			if (args->arg.nd_nbuf == NULL) {
8520Sstevel@tonic-gate 				_nderror = ND_BADARG;
8530Sstevel@tonic-gate 				return (_nderror);
8540Sstevel@tonic-gate 			}
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 			/*
8570Sstevel@tonic-gate 			 * Validate the address which was passed
8580Sstevel@tonic-gate 			 * as the request.
8590Sstevel@tonic-gate 			 */
860132Srobinson 			/* LINTED pointer cast */
8610Sstevel@tonic-gate 			sin = (struct sockaddr_in *)args->arg.nd_nbuf->buf;
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 			if ((args->arg.nd_nbuf->len !=
864*7752SMichen.Chang@Sun.COM 			    sizeof (struct sockaddr_in)) ||
8650Sstevel@tonic-gate 			    (sin->sin_family != AF_INET)) {
8660Sstevel@tonic-gate 				_nderror = ND_BADARG;
8670Sstevel@tonic-gate 				return (_nderror);
8680Sstevel@tonic-gate 			}
8690Sstevel@tonic-gate 		}
8700Sstevel@tonic-gate 		break;
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 		case NETDIR_BY6:
8730Sstevel@tonic-gate 		case NETDIR_BY_NOSRV6:
8740Sstevel@tonic-gate 		{
8750Sstevel@tonic-gate 			struct sockaddr_in6 *sin6;
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 			if (args->arg.nd_nbuf == NULL) {
8780Sstevel@tonic-gate 				_nderror = ND_BADARG;
8790Sstevel@tonic-gate 				return (_nderror);
8800Sstevel@tonic-gate 			}
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 			/*
8830Sstevel@tonic-gate 			 * Validate the address which was passed
8840Sstevel@tonic-gate 			 * as the request.
8850Sstevel@tonic-gate 			 */
886132Srobinson 			/* LINTED pointer cast */
8870Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)args->arg.nd_nbuf->buf;
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 			if ((args->arg.nd_nbuf->len !=
890*7752SMichen.Chang@Sun.COM 			    sizeof (struct sockaddr_in6)) ||
8910Sstevel@tonic-gate 			    (sin6->sin6_family != AF_INET6)) {
8920Sstevel@tonic-gate 				_nderror = ND_BADARG;
8930Sstevel@tonic-gate 				return (_nderror);
8940Sstevel@tonic-gate 			}
8950Sstevel@tonic-gate 		}
8960Sstevel@tonic-gate 		break;
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	/*
9010Sstevel@tonic-gate 	 * 2. Most common scenario. This is the way we ship /etc/netconfig.
9020Sstevel@tonic-gate 	 *    Emphasis on improving performance in the "if" part.
9030Sstevel@tonic-gate 	 */
9040Sstevel@tonic-gate 	if (nconf->nc_nlookups == 0) {
9050Sstevel@tonic-gate 		struct hostent	*he = NULL, *tmphe;
9060Sstevel@tonic-gate 		struct servent	*se = NULL;
9070Sstevel@tonic-gate 		nss_XbyY_buf_t	*ndbuf4host = 0;
9080Sstevel@tonic-gate 		nss_XbyY_buf_t	*ndbuf4serv = 0;
9090Sstevel@tonic-gate 		char	*proto =
9100Sstevel@tonic-gate 		    (strcmp(nconf->nc_proto, NC_TCP) == 0) ? NC_TCP : NC_UDP;
9110Sstevel@tonic-gate 		struct	sockaddr_in *sa;
9120Sstevel@tonic-gate 		struct sockaddr_in6 *sin6;
9130Sstevel@tonic-gate 		struct in_addr *addr4 = 0;
9140Sstevel@tonic-gate 		struct in6_addr v4mapbuf;
9150Sstevel@tonic-gate 		int	h_errnop;
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	switch (args->op_t) {
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 		case NSS_HOST:
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 		he = DOOR_GETHOSTBYADDR_R(args->arg.nss.host.addr,
9220Sstevel@tonic-gate 		    args->arg.nss.host.len, args->arg.nss.host.type,
9230Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
9240Sstevel@tonic-gate 		    args->arg.nss.host.buflen,
9250Sstevel@tonic-gate 		    res->nss.host.herrno_p);
9260Sstevel@tonic-gate 		if (he == 0)
9270Sstevel@tonic-gate 			_nderror = ND_NOHOST;
9280Sstevel@tonic-gate 		else
9290Sstevel@tonic-gate 			_nderror = ND_OK;
9300Sstevel@tonic-gate 		return (_nderror);
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 		case NSS_HOST6:
9340Sstevel@tonic-gate 		he = DOOR_GETIPNODEBYADDR_R(args->arg.nss.host.addr,
9350Sstevel@tonic-gate 		    args->arg.nss.host.len, args->arg.nss.host.type,
9360Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
9370Sstevel@tonic-gate 		    args->arg.nss.host.buflen,
9380Sstevel@tonic-gate 		    res->nss.host.herrno_p);
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 		if (he == 0)
9410Sstevel@tonic-gate 			return (ND_NOHOST);
9420Sstevel@tonic-gate 		return (ND_OK);
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 		case NSS_SERV:
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 		se = _switch_getservbyport_r(args->arg.nss.serv.port,
9480Sstevel@tonic-gate 		    args->arg.nss.serv.proto,
9490Sstevel@tonic-gate 		    res->nss.serv, args->arg.nss.serv.buf,
9500Sstevel@tonic-gate 		    args->arg.nss.serv.buflen);
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 		if (se == 0)
9530Sstevel@tonic-gate 			_nderror = ND_NOSERV;
9540Sstevel@tonic-gate 		else
9550Sstevel@tonic-gate 			_nderror = ND_OK;
9560Sstevel@tonic-gate 		return (_nderror);
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 		case NETDIR_BY:
9590Sstevel@tonic-gate 		case NETDIR_BY_NOSRV:
9600Sstevel@tonic-gate 
961132Srobinson 		ndbuf4serv = _nss_XbyY_buf_alloc(sizeof (struct servent),
962*7752SMichen.Chang@Sun.COM 		    NSS_BUFLEN_SERVICES);
9630Sstevel@tonic-gate 		if (ndbuf4serv == 0) {
9640Sstevel@tonic-gate 			_nderror = ND_NOMEM;
9650Sstevel@tonic-gate 			return (_nderror);
9660Sstevel@tonic-gate 		}
967132Srobinson 		/* LINTED pointer cast */
9680Sstevel@tonic-gate 		sa = (struct sockaddr_in *)(args->arg.nd_nbuf->buf);
9690Sstevel@tonic-gate 		addr4 = (struct in_addr *)&(sa->sin_addr);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 		/*
9720Sstevel@tonic-gate 		 * if NETDIR_BY_NOSRV or port == 0 skip the service
9730Sstevel@tonic-gate 		 * lookup.
9740Sstevel@tonic-gate 		 */
9750Sstevel@tonic-gate 		if (args->op_t != NETDIR_BY_NOSRV && sa->sin_port != 0) {
9760Sstevel@tonic-gate 			se = _switch_getservbyport_r(sa->sin_port, proto,
9770Sstevel@tonic-gate 			    ndbuf4serv->result, ndbuf4serv->buffer,
978*7752SMichen.Chang@Sun.COM 			    ndbuf4serv->buflen);
9790Sstevel@tonic-gate 			if (!se) {
9800Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4serv);
9810Sstevel@tonic-gate 				/*
9820Sstevel@tonic-gate 				 * We can live with this - i.e. the address
9830Sstevel@tonic-gate 				 * does not
9840Sstevel@tonic-gate 				 * belong to a well known service. The caller
9850Sstevel@tonic-gate 				 * traditionally accepts a stringified port
9860Sstevel@tonic-gate 				 * number
9870Sstevel@tonic-gate 				 * as the service name. The state of se is used
9880Sstevel@tonic-gate 				 * ahead to indicate the same.
9890Sstevel@tonic-gate 				 * However, we do not tolerate this nonsense
9900Sstevel@tonic-gate 				 * when we cannot get a host name. See below.
9910Sstevel@tonic-gate 				 */
9920Sstevel@tonic-gate 			}
9930Sstevel@tonic-gate 		}
9940Sstevel@tonic-gate 
995132Srobinson 		ndbuf4host = _nss_XbyY_buf_alloc(sizeof (struct hostent),
996*7752SMichen.Chang@Sun.COM 		    NSS_BUFLEN_HOSTS);
9970Sstevel@tonic-gate 		if (ndbuf4host == 0) {
9980Sstevel@tonic-gate 			if (ndbuf4serv)
9990Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4serv);
10000Sstevel@tonic-gate 			_nderror = ND_NOMEM;
10010Sstevel@tonic-gate 			return (_nderror);
10020Sstevel@tonic-gate 		}
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 		/*
10050Sstevel@tonic-gate 		 * Since we're going to search the ipnodes (v6) path first,
10060Sstevel@tonic-gate 		 * we need to treat the address as a v4mapped address.
10070Sstevel@tonic-gate 		 */
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 		IN6_INADDR_TO_V4MAPPED(addr4, &v4mapbuf);
10100Sstevel@tonic-gate 		if ((tmphe = DOOR_GETIPNODEBYADDR_R((char *)&v4mapbuf,
10110Sstevel@tonic-gate 		    16, AF_INET6, ndbuf4host->result,
1012*7752SMichen.Chang@Sun.COM 		    ndbuf4host->buffer,
1013*7752SMichen.Chang@Sun.COM 		    ndbuf4host->buflen, &h_errnop)) != NULL)
10140Sstevel@tonic-gate 			he = __mappedtov4(tmphe, &h_errnop);
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 		if (!he) {
10170Sstevel@tonic-gate 			/* Failover case, try hosts db for v4 address */
10180Sstevel@tonic-gate 			he = DOOR_GETHOSTBYADDR_R((char *)
1019*7752SMichen.Chang@Sun.COM 			    &(sa->sin_addr.s_addr), 4,
1020*7752SMichen.Chang@Sun.COM 			    sa->sin_family, ndbuf4host->result,
1021*7752SMichen.Chang@Sun.COM 			    ndbuf4host->buffer, ndbuf4host->buflen,
1022*7752SMichen.Chang@Sun.COM 			    &h_errnop);
10230Sstevel@tonic-gate 			if (!he) {
10240Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4host);
10250Sstevel@tonic-gate 				if (ndbuf4serv)
10260Sstevel@tonic-gate 					NSS_XbyY_FREE(&ndbuf4serv);
10270Sstevel@tonic-gate 				_nderror = __herrno2netdir(h_errnop);
10280Sstevel@tonic-gate 				return (_nderror);
10290Sstevel@tonic-gate 			}
10300Sstevel@tonic-gate 			/*
10310Sstevel@tonic-gate 			 * Convert host names and service names into hostserv
10320Sstevel@tonic-gate 			 * pairs. malloc's will be done, freed using
10330Sstevel@tonic-gate 			 * netdir_free.
10340Sstevel@tonic-gate 			 */
10350Sstevel@tonic-gate 			h_errnop = hsents2ndhostservs(he, se,
10360Sstevel@tonic-gate 			    sa->sin_port, res->nd_hslist);
10370Sstevel@tonic-gate 		} else {
10380Sstevel@tonic-gate 			/*
10390Sstevel@tonic-gate 			 * Convert host names and service names into hostserv
10400Sstevel@tonic-gate 			 * pairs. malloc's will be done, freed using
10410Sstevel@tonic-gate 			 * netdir_free.
10420Sstevel@tonic-gate 			 */
10430Sstevel@tonic-gate 			h_errnop = hsents2ndhostservs(he, se,
10440Sstevel@tonic-gate 			    sa->sin_port, res->nd_hslist);
10450Sstevel@tonic-gate 			freehostent(he);
10460Sstevel@tonic-gate 		}
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 		NSS_XbyY_FREE(&ndbuf4host);
10490Sstevel@tonic-gate 		if (ndbuf4serv)
1050*7752SMichen.Chang@Sun.COM 			NSS_XbyY_FREE(&ndbuf4serv);
10510Sstevel@tonic-gate 		_nderror = __herrno2netdir(h_errnop);
10520Sstevel@tonic-gate 		return (_nderror);
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 		case NETDIR_BY6:
10550Sstevel@tonic-gate 		case NETDIR_BY_NOSRV6:
10560Sstevel@tonic-gate 
1057132Srobinson 		ndbuf4serv = _nss_XbyY_buf_alloc(sizeof (struct servent),
1058*7752SMichen.Chang@Sun.COM 		    NSS_BUFLEN_SERVICES);
10590Sstevel@tonic-gate 		if (ndbuf4serv == 0) {
10600Sstevel@tonic-gate 			_nderror = ND_NOMEM;
10610Sstevel@tonic-gate 			return (ND_NOMEM);
10620Sstevel@tonic-gate 		}
1063132Srobinson 		/* LINTED pointer cast */
10640Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)(args->arg.nd_nbuf->buf);
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 		/*
10670Sstevel@tonic-gate 		 * if NETDIR_BY_NOSRV6 or port == 0 skip the service
10680Sstevel@tonic-gate 		 * lookup.
10690Sstevel@tonic-gate 		 */
10700Sstevel@tonic-gate 		if (args->op_t != NETDIR_BY_NOSRV6 && sin6->sin6_port == 0) {
10710Sstevel@tonic-gate 			se = _switch_getservbyport_r(sin6->sin6_port, proto,
10720Sstevel@tonic-gate 			    ndbuf4serv->result, ndbuf4serv->buffer,
1073*7752SMichen.Chang@Sun.COM 			    ndbuf4serv->buflen);
10740Sstevel@tonic-gate 			if (!se) {
10750Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4serv);
10760Sstevel@tonic-gate 				/*
10770Sstevel@tonic-gate 				 * We can live with this - i.e. the address does
10780Sstevel@tonic-gate 				 * not * belong to a well known service. The
10790Sstevel@tonic-gate 				 * caller traditionally accepts a stringified
10800Sstevel@tonic-gate 				 * port number
10810Sstevel@tonic-gate 				 * as the service name. The state of se is used
10820Sstevel@tonic-gate 				 * ahead to indicate the same.
10830Sstevel@tonic-gate 				 * However, we do not tolerate this nonsense
10840Sstevel@tonic-gate 				 * when we cannot get a host name. See below.
10850Sstevel@tonic-gate 				 */
10860Sstevel@tonic-gate 			}
10870Sstevel@tonic-gate 		}
10880Sstevel@tonic-gate 
1089132Srobinson 		ndbuf4host = _nss_XbyY_buf_alloc(sizeof (struct hostent),
1090*7752SMichen.Chang@Sun.COM 		    NSS_BUFLEN_HOSTS);
10910Sstevel@tonic-gate 		if (ndbuf4host == 0) {
10920Sstevel@tonic-gate 			if (ndbuf4serv)
10930Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4serv);
10940Sstevel@tonic-gate 			_nderror = ND_NOMEM;
10950Sstevel@tonic-gate 			return (_nderror);
10960Sstevel@tonic-gate 		}
10970Sstevel@tonic-gate 		he = DOOR_GETIPNODEBYADDR_R((char *)&(sin6->sin6_addr),
10980Sstevel@tonic-gate 		    16, sin6->sin6_family, ndbuf4host->result,
1099*7752SMichen.Chang@Sun.COM 		    ndbuf4host->buffer,
1100*7752SMichen.Chang@Sun.COM 		    ndbuf4host->buflen, &h_errnop);
11010Sstevel@tonic-gate 		if (!he) {
11020Sstevel@tonic-gate 			NSS_XbyY_FREE(&ndbuf4host);
11030Sstevel@tonic-gate 			if (ndbuf4serv)
1104*7752SMichen.Chang@Sun.COM 				NSS_XbyY_FREE(&ndbuf4serv);
11050Sstevel@tonic-gate 			_nderror = __herrno2netdir(h_errnop);
11060Sstevel@tonic-gate 			return (_nderror);
11070Sstevel@tonic-gate 		}
11080Sstevel@tonic-gate 		/*
11090Sstevel@tonic-gate 		 * Convert host names and service names into hostserv
11100Sstevel@tonic-gate 		 * pairs. malloc's will be done, freed using netdir_free.
11110Sstevel@tonic-gate 		 */
11120Sstevel@tonic-gate 		h_errnop = hsents2ndhostservs(he, se,
11130Sstevel@tonic-gate 		    sin6->sin6_port, res->nd_hslist);
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 		NSS_XbyY_FREE(&ndbuf4host);
11160Sstevel@tonic-gate 		if (ndbuf4serv)
1117*7752SMichen.Chang@Sun.COM 			NSS_XbyY_FREE(&ndbuf4serv);
11180Sstevel@tonic-gate 		_nderror = __herrno2netdir(h_errnop);
11190Sstevel@tonic-gate 		return (_nderror);
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 		default:
11220Sstevel@tonic-gate 		_nderror = ND_BADARG;
11230Sstevel@tonic-gate 		return (_nderror); /* should never happen */
11240Sstevel@tonic-gate 	}
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	}
11270Sstevel@tonic-gate 	/*
11280Sstevel@tonic-gate 	 * 3. We come this far only if nametoaddr libs are specified for
11290Sstevel@tonic-gate 	 *    inet transports and we are called by gethost/servbyname only.
11300Sstevel@tonic-gate 	 */
11310Sstevel@tonic-gate 	switch (args->op_t) {
11320Sstevel@tonic-gate 		struct	netbuf nbuf;
11330Sstevel@tonic-gate 		struct	nd_hostservlist *addrs;
11340Sstevel@tonic-gate 		struct	sockaddr_in sa;
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 		case NSS_HOST:
11370Sstevel@tonic-gate 
1138132Srobinson 		/* LINTED pointer cast */
11390Sstevel@tonic-gate 		sa.sin_addr.s_addr = *(uint32_t *)args->arg.nss.host.addr;
11400Sstevel@tonic-gate 		sa.sin_family = AF_INET;
11410Sstevel@tonic-gate 		/* Hopefully, third-parties get this optimization */
11420Sstevel@tonic-gate 		sa.sin_port = 0;
11430Sstevel@tonic-gate 		nbuf.buf = (char *)&sa;
11440Sstevel@tonic-gate 		nbuf.len = nbuf.maxlen = sizeof (sa);
11450Sstevel@tonic-gate 		if ((_nderror = __classic_netdir_getbyaddr(nconf,
1146*7752SMichen.Chang@Sun.COM 		    &addrs, &nbuf)) != 0) {
11470Sstevel@tonic-gate 			*(res->nss.host.herrno_p) = nd2herrno(_nderror);
11480Sstevel@tonic-gate 			return (_nderror);
11490Sstevel@tonic-gate 		}
11500Sstevel@tonic-gate 		/*
11510Sstevel@tonic-gate 		 * convert the host-serv pairs into h_aliases and hent.
11520Sstevel@tonic-gate 		 */
11530Sstevel@tonic-gate 		_nderror = ndhostserv2hent(&nbuf, addrs, res->nss.host.hent,
11540Sstevel@tonic-gate 		    args->arg.nss.host.buf, args->arg.nss.host.buflen);
11550Sstevel@tonic-gate 		if (_nderror != ND_OK)
11560Sstevel@tonic-gate 			*(res->nss.host.herrno_p) = nd2herrno(_nderror);
11570Sstevel@tonic-gate 		netdir_free((char *)addrs, ND_HOSTSERVLIST);
11580Sstevel@tonic-gate 		return (_nderror);
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 		case NSS_SERV:
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 		if (args->arg.nss.serv.proto == NULL) {
11630Sstevel@tonic-gate 			/*
11640Sstevel@tonic-gate 			 * A similar HACK showed up in Solaris 2.3.
11650Sstevel@tonic-gate 			 * The caller wild-carded proto -- i.e. will
11660Sstevel@tonic-gate 			 * accept a match on tcp or udp for the port
11670Sstevel@tonic-gate 			 * number. Since we have no hope of getting
11680Sstevel@tonic-gate 			 * directly to a name service switch backend
11690Sstevel@tonic-gate 			 * from here that understands this semantics,
11700Sstevel@tonic-gate 			 * we try calling the netdir interfaces first
11710Sstevel@tonic-gate 			 * with "tcp" and then "udp".
11720Sstevel@tonic-gate 			 */
11730Sstevel@tonic-gate 			args->arg.nss.serv.proto = "tcp";
11740Sstevel@tonic-gate 			_nderror = _get_hostserv_inetnetdir_byaddr(nconf, args,
11750Sstevel@tonic-gate 			    res);
11760Sstevel@tonic-gate 			if (_nderror != ND_OK) {
11770Sstevel@tonic-gate 				args->arg.nss.serv.proto = "udp";
11780Sstevel@tonic-gate 				_nderror =
11790Sstevel@tonic-gate 				    _get_hostserv_inetnetdir_byaddr(nconf,
1180*7752SMichen.Chang@Sun.COM 				    args, res);
11810Sstevel@tonic-gate 			}
11820Sstevel@tonic-gate 			return (_nderror);
11830Sstevel@tonic-gate 		}
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 		/*
11860Sstevel@tonic-gate 		 * Third-party nametoaddr_libs should be optimized for
11870Sstevel@tonic-gate 		 * this case. It also gives a special semantics twist to
11880Sstevel@tonic-gate 		 * netdir_getbyaddr. Only for the INADDR_ANY case, it gives
11890Sstevel@tonic-gate 		 * higher priority to service lookups (over host lookups).
11900Sstevel@tonic-gate 		 * If service lookup fails, the backend returns ND_NOSERV to
11910Sstevel@tonic-gate 		 * facilitate lookup in the "next" naming service.
11920Sstevel@tonic-gate 		 * BugId: 1075403.
11930Sstevel@tonic-gate 		 */
11940Sstevel@tonic-gate 		sa.sin_addr.s_addr = INADDR_ANY;
11950Sstevel@tonic-gate 		sa.sin_family = AF_INET;
11960Sstevel@tonic-gate 		sa.sin_port = (ushort_t)args->arg.nss.serv.port;
11970Sstevel@tonic-gate 		sa.sin_zero[0] = '\0';
11980Sstevel@tonic-gate 		nbuf.buf = (char *)&sa;
11990Sstevel@tonic-gate 		nbuf.len = nbuf.maxlen = sizeof (sa);
12000Sstevel@tonic-gate 		if ((_nderror = __classic_netdir_getbyaddr(nconf,
1201*7752SMichen.Chang@Sun.COM 		    &addrs, &nbuf)) != ND_OK) {
12020Sstevel@tonic-gate 			return (_nderror);
12030Sstevel@tonic-gate 		}
12040Sstevel@tonic-gate 		/*
12050Sstevel@tonic-gate 		 * convert the host-serv pairs into s_aliases and servent.
12060Sstevel@tonic-gate 		 */
12070Sstevel@tonic-gate 		_nderror = ndhostserv2srent(args->arg.nss.serv.port,
12080Sstevel@tonic-gate 		    args->arg.nss.serv.proto, addrs, res->nss.serv,
12090Sstevel@tonic-gate 		    args->arg.nss.serv.buf, args->arg.nss.serv.buflen);
12100Sstevel@tonic-gate 		netdir_free((char *)addrs, ND_HOSTSERVLIST);
12110Sstevel@tonic-gate 		return (_nderror);
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 		default:
12140Sstevel@tonic-gate 		_nderror = ND_BADARG;
12150Sstevel@tonic-gate 		return (_nderror); /* should never happen */
12160Sstevel@tonic-gate 	}
12170Sstevel@tonic-gate }
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate /*
12200Sstevel@tonic-gate  * Part II: Name Service Switch interfacing routines.
12210Sstevel@tonic-gate  */
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_hosts);
12240Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_ipnodes);
12250Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_services);
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate /*
12290Sstevel@tonic-gate  * There is a copy of __nss2herrno() in nsswitch/files/gethostent.c.
12300Sstevel@tonic-gate  * It is there because /etc/lib/nss_files.so.1 cannot call
12310Sstevel@tonic-gate  * routines in libnsl.  Care should be taken to keep the two copies
1232*7752SMichen.Chang@Sun.COM  * in sync (except that case NSS_NISSERVDNS_TRYAGAIN is not needed in
1233*7752SMichen.Chang@Sun.COM  * nsswitch/files).
12340Sstevel@tonic-gate  */
12350Sstevel@tonic-gate int
__nss2herrno(nss_status_t nsstat)12360Sstevel@tonic-gate __nss2herrno(nss_status_t nsstat)
12370Sstevel@tonic-gate {
12380Sstevel@tonic-gate 	switch (nsstat) {
12390Sstevel@tonic-gate 	case NSS_SUCCESS:
12400Sstevel@tonic-gate 		/* no macro-defined success code for h_errno */
12410Sstevel@tonic-gate 		return (0);
12420Sstevel@tonic-gate 	case NSS_NOTFOUND:
12430Sstevel@tonic-gate 		return (HOST_NOT_FOUND);
12440Sstevel@tonic-gate 	case NSS_TRYAGAIN:
12450Sstevel@tonic-gate 		return (TRY_AGAIN);
12460Sstevel@tonic-gate 	case NSS_UNAVAIL:
12470Sstevel@tonic-gate 		return (NO_RECOVERY);
1248*7752SMichen.Chang@Sun.COM 	case NSS_NISSERVDNS_TRYAGAIN:
1249*7752SMichen.Chang@Sun.COM 		return (TRY_AGAIN);
12500Sstevel@tonic-gate 	}
1251*7752SMichen.Chang@Sun.COM 	/* anything else */
1252*7752SMichen.Chang@Sun.COM 	return (NO_RECOVERY);
12530Sstevel@tonic-gate }
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate nss_status_t
_herrno2nss(int h_errno)12560Sstevel@tonic-gate _herrno2nss(int h_errno)
12570Sstevel@tonic-gate {
12580Sstevel@tonic-gate 	switch (h_errno) {
12590Sstevel@tonic-gate 	case 0:
12600Sstevel@tonic-gate 		return (NSS_SUCCESS);
12610Sstevel@tonic-gate 	case TRY_AGAIN:
12620Sstevel@tonic-gate 		return (NSS_TRYAGAIN);
12630Sstevel@tonic-gate 	case NO_RECOVERY:
12640Sstevel@tonic-gate 	case NETDB_INTERNAL:
12650Sstevel@tonic-gate 		return (NSS_UNAVAIL);
12660Sstevel@tonic-gate 	case HOST_NOT_FOUND:
12670Sstevel@tonic-gate 	case NO_DATA:
12680Sstevel@tonic-gate 	default:
12690Sstevel@tonic-gate 		return (NSS_NOTFOUND);
12700Sstevel@tonic-gate 	}
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate static int
__herrno2netdir(int h_errnop)12740Sstevel@tonic-gate __herrno2netdir(int h_errnop)
12750Sstevel@tonic-gate {
12760Sstevel@tonic-gate 	switch (h_errnop) {
12770Sstevel@tonic-gate 		case 0:
12780Sstevel@tonic-gate 			return (ND_OK);
12790Sstevel@tonic-gate 		case HOST_NOT_FOUND:
12800Sstevel@tonic-gate 			return (ND_NOHOST);
12810Sstevel@tonic-gate 		case TRY_AGAIN:
12820Sstevel@tonic-gate 			return (ND_TRY_AGAIN);
12830Sstevel@tonic-gate 		case NO_RECOVERY:
12840Sstevel@tonic-gate 		case NETDB_INTERNAL:
12850Sstevel@tonic-gate 			return (ND_NO_RECOVERY);
12860Sstevel@tonic-gate 		case NO_DATA:
12870Sstevel@tonic-gate 			return (ND_NO_DATA);
12880Sstevel@tonic-gate 		default:
12890Sstevel@tonic-gate 			return (ND_NOHOST);
12900Sstevel@tonic-gate 	}
12910Sstevel@tonic-gate }
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate /*
12940Sstevel@tonic-gate  * The _switch_getXXbyYY_r() routines should be static.  They used to
12950Sstevel@tonic-gate  * be exported in SunOS 5.3, and in fact publicised as work-around
12960Sstevel@tonic-gate  * interfaces for getting CNAME/aliases, and therefore, we preserve
12970Sstevel@tonic-gate  * their signatures here. Just in case.
12980Sstevel@tonic-gate  */
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate struct hostent *
_switch_gethostbyname_r(const char * name,struct hostent * result,char * buffer,int buflen,int * h_errnop)13010Sstevel@tonic-gate _switch_gethostbyname_r(const char *name, struct hostent *result, char *buffer,
13020Sstevel@tonic-gate     int buflen, int *h_errnop)
13030Sstevel@tonic-gate {
13040Sstevel@tonic-gate 	nss_XbyY_args_t arg;
13050Sstevel@tonic-gate 	nss_status_t	res;
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent);
13080Sstevel@tonic-gate 	arg.key.name	= name;
13090Sstevel@tonic-gate 	arg.stayopen	= 0;
13100Sstevel@tonic-gate 	res = nss_search(&db_root_hosts, _nss_initf_hosts,
13110Sstevel@tonic-gate 	    NSS_DBOP_HOSTS_BYNAME, &arg);
13120Sstevel@tonic-gate 	arg.status = res;
13130Sstevel@tonic-gate 	*h_errnop = arg.h_errno;
13140Sstevel@tonic-gate 	if (arg.returnval != NULL)
13150Sstevel@tonic-gate 		order_haddrlist_af(result->h_addrtype, result->h_addr_list);
13160Sstevel@tonic-gate 	return ((struct hostent *)NSS_XbyY_FINI(&arg));
13170Sstevel@tonic-gate }
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate struct hostent *
_switch_getipnodebyname_r(const char * name,struct hostent * result,char * buffer,int buflen,int af_family,int flags,int * h_errnop)13200Sstevel@tonic-gate _switch_getipnodebyname_r(const char *name, struct hostent *result,
13210Sstevel@tonic-gate     char *buffer, int buflen, int af_family, int flags, int *h_errnop)
13220Sstevel@tonic-gate {
13230Sstevel@tonic-gate 	nss_XbyY_args_t arg;
13240Sstevel@tonic-gate 	nss_status_t	res;
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6);
13270Sstevel@tonic-gate 	arg.key.ipnode.name	= name;
13280Sstevel@tonic-gate 	arg.key.ipnode.af_family = af_family;
13290Sstevel@tonic-gate 	arg.key.ipnode.flags = flags;
13300Sstevel@tonic-gate 	arg.stayopen	= 0;
13310Sstevel@tonic-gate 	res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes,
13320Sstevel@tonic-gate 	    NSS_DBOP_IPNODES_BYNAME, &arg);
13330Sstevel@tonic-gate 	arg.status = res;
13340Sstevel@tonic-gate 	*h_errnop = arg.h_errno;
13350Sstevel@tonic-gate 	if (arg.returnval != NULL)
13360Sstevel@tonic-gate 		order_haddrlist_af(result->h_addrtype, result->h_addr_list);
13370Sstevel@tonic-gate 	return ((struct hostent *)NSS_XbyY_FINI(&arg));
13380Sstevel@tonic-gate }
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate struct hostent *
_switch_gethostbyaddr_r(const char * addr,int len,int type,struct hostent * result,char * buffer,int buflen,int * h_errnop)13410Sstevel@tonic-gate _switch_gethostbyaddr_r(const char *addr, int len, int type,
13420Sstevel@tonic-gate     struct hostent *result, char *buffer, int buflen, int *h_errnop)
13430Sstevel@tonic-gate {
13440Sstevel@tonic-gate 	nss_XbyY_args_t arg;
13450Sstevel@tonic-gate 	nss_status_t	res;
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent);
13480Sstevel@tonic-gate 	arg.key.hostaddr.addr	= addr;
13490Sstevel@tonic-gate 	arg.key.hostaddr.len	= len;
13500Sstevel@tonic-gate 	arg.key.hostaddr.type	= type;
13510Sstevel@tonic-gate 	arg.stayopen		= 0;
13520Sstevel@tonic-gate 	res = nss_search(&db_root_hosts, _nss_initf_hosts,
13530Sstevel@tonic-gate 	    NSS_DBOP_HOSTS_BYADDR, &arg);
13540Sstevel@tonic-gate 	arg.status = res;
13550Sstevel@tonic-gate 	*h_errnop = arg.h_errno;
13560Sstevel@tonic-gate 	return (struct hostent *)NSS_XbyY_FINI(&arg);
13570Sstevel@tonic-gate }
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate struct hostent *
_switch_getipnodebyaddr_r(const char * addr,int len,int type,struct hostent * result,char * buffer,int buflen,int * h_errnop)13600Sstevel@tonic-gate _switch_getipnodebyaddr_r(const char *addr, int len, int type,
13610Sstevel@tonic-gate     struct hostent *result, char *buffer, int buflen, int *h_errnop)
13620Sstevel@tonic-gate {
13630Sstevel@tonic-gate 	nss_XbyY_args_t arg;
13640Sstevel@tonic-gate 	nss_status_t	res;
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6);
13670Sstevel@tonic-gate 	arg.key.hostaddr.addr	= addr;
13680Sstevel@tonic-gate 	arg.key.hostaddr.len	= len;
13690Sstevel@tonic-gate 	arg.key.hostaddr.type	= type;
13700Sstevel@tonic-gate 	arg.stayopen		= 0;
13710Sstevel@tonic-gate 	res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes,
13720Sstevel@tonic-gate 	    NSS_DBOP_IPNODES_BYADDR, &arg);
13730Sstevel@tonic-gate 	arg.status = res;
13740Sstevel@tonic-gate 	*h_errnop = arg.h_errno;
13750Sstevel@tonic-gate 	return (struct hostent *)NSS_XbyY_FINI(&arg);
13760Sstevel@tonic-gate }
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate static void
_nss_initf_services(nss_db_params_t * p)13790Sstevel@tonic-gate _nss_initf_services(nss_db_params_t *p)
13800Sstevel@tonic-gate {
13810Sstevel@tonic-gate 	p->name	= NSS_DBNAM_SERVICES;
13820Sstevel@tonic-gate 	p->default_config = NSS_DEFCONF_SERVICES;
13830Sstevel@tonic-gate }
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate struct servent *
_switch_getservbyname_r(const char * name,const char * proto,struct servent * result,char * buffer,int buflen)13860Sstevel@tonic-gate _switch_getservbyname_r(const char *name, const char *proto,
13870Sstevel@tonic-gate     struct servent *result, char *buffer, int buflen)
13880Sstevel@tonic-gate {
13890Sstevel@tonic-gate 	nss_XbyY_args_t arg;
13900Sstevel@tonic-gate 	nss_status_t	res;
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent);
13930Sstevel@tonic-gate 	arg.key.serv.serv.name	= name;
13940Sstevel@tonic-gate 	arg.key.serv.proto	= proto;
13950Sstevel@tonic-gate 	arg.stayopen		= 0;
13960Sstevel@tonic-gate 	res = nss_search(&db_root_services, _nss_initf_services,
13970Sstevel@tonic-gate 	    NSS_DBOP_SERVICES_BYNAME, &arg);
13980Sstevel@tonic-gate 	arg.status = res;
13990Sstevel@tonic-gate 	return ((struct servent *)NSS_XbyY_FINI(&arg));
14000Sstevel@tonic-gate }
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate struct servent *
_switch_getservbyport_r(int port,const char * proto,struct servent * result,char * buffer,int buflen)14030Sstevel@tonic-gate _switch_getservbyport_r(int port, const char *proto, struct servent *result,
14040Sstevel@tonic-gate     char *buffer, int buflen)
14050Sstevel@tonic-gate {
14060Sstevel@tonic-gate 	nss_XbyY_args_t arg;
14070Sstevel@tonic-gate 	nss_status_t	res;
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent);
14100Sstevel@tonic-gate 	arg.key.serv.serv.port	= port;
14110Sstevel@tonic-gate 	arg.key.serv.proto	= proto;
14120Sstevel@tonic-gate 	arg.stayopen		= 0;
14130Sstevel@tonic-gate 	res = nss_search(&db_root_services, _nss_initf_services,
14140Sstevel@tonic-gate 	    NSS_DBOP_SERVICES_BYPORT, &arg);
14150Sstevel@tonic-gate 	arg.status = res;
14160Sstevel@tonic-gate 	return ((struct servent *)NSS_XbyY_FINI(&arg));
14170Sstevel@tonic-gate }
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate /*
14210Sstevel@tonic-gate  * Return values: 0 = success, 1 = parse error, 2 = erange ...
14220Sstevel@tonic-gate  * The structure pointer passed in is a structure in the caller's space
14230Sstevel@tonic-gate  * wherein the field pointers would be set to areas in the buffer if
14240Sstevel@tonic-gate  * need be. instring and buffer should be separate areas.
14250Sstevel@tonic-gate  *
14260Sstevel@tonic-gate  * Defined here because we need it and we (libnsl) cannot have a dependency
14270Sstevel@tonic-gate  * on libsocket (however, libsocket always depends on libnsl).
14280Sstevel@tonic-gate  */
14290Sstevel@tonic-gate int
str2servent(const char * instr,int lenstr,void * ent,char * buffer,int buflen)14300Sstevel@tonic-gate str2servent(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
14310Sstevel@tonic-gate {
14320Sstevel@tonic-gate 	struct servent	*serv	= (struct servent *)ent;
14330Sstevel@tonic-gate 	const char	*p, *fieldstart, *limit, *namestart;
14340Sstevel@tonic-gate 	ssize_t		fieldlen, namelen = 0;
14350Sstevel@tonic-gate 	char		numbuf[12];
14360Sstevel@tonic-gate 	char		*numend;
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	if ((instr >= buffer && (buffer + buflen) > instr) ||
14390Sstevel@tonic-gate 	    (buffer >= instr && (instr + lenstr) > buffer)) {
14400Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
14410Sstevel@tonic-gate 	}
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	p = instr;
14440Sstevel@tonic-gate 	limit = p + lenstr;
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 	while (p < limit && isspace(*p)) {
14470Sstevel@tonic-gate 		p++;
14480Sstevel@tonic-gate 	}
14490Sstevel@tonic-gate 	namestart = p;
14500Sstevel@tonic-gate 	while (p < limit && !isspace(*p)) {
14510Sstevel@tonic-gate 		p++;		/* Skip over the canonical name */
14520Sstevel@tonic-gate 	}
14530Sstevel@tonic-gate 	namelen = p - namestart;
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate 	if (buflen <= namelen) { /* not enough buffer */
14560Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
14570Sstevel@tonic-gate 	}
14580Sstevel@tonic-gate 	(void) memcpy(buffer, namestart, namelen);
14590Sstevel@tonic-gate 	buffer[namelen] = '\0';
14600Sstevel@tonic-gate 	serv->s_name = buffer;
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 	while (p < limit && isspace(*p)) {
14630Sstevel@tonic-gate 		p++;
14640Sstevel@tonic-gate 	}
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate 	fieldstart = p;
14670Sstevel@tonic-gate 	do {
14680Sstevel@tonic-gate 		if (p > limit || isspace(*p)) {
14690Sstevel@tonic-gate 			/* Syntax error -- no port/proto */
14700Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
14710Sstevel@tonic-gate 		}
1472*7752SMichen.Chang@Sun.COM 	} while (*p++ != '/');
14730Sstevel@tonic-gate 	fieldlen = p - fieldstart - 1;
14740Sstevel@tonic-gate 	if (fieldlen == 0 || fieldlen >= sizeof (numbuf)) {
14750Sstevel@tonic-gate 		/* Syntax error -- supposed number is empty or too long */
14760Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
14770Sstevel@tonic-gate 	}
14780Sstevel@tonic-gate 	(void) memcpy(numbuf, fieldstart, fieldlen);
14790Sstevel@tonic-gate 	numbuf[fieldlen] = '\0';
14800Sstevel@tonic-gate 	serv->s_port = htons((int)strtol(numbuf, &numend, 10));
14810Sstevel@tonic-gate 	if (*numend != '\0') {
14820Sstevel@tonic-gate 		/* Syntax error -- port number isn't a number */
14830Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
14840Sstevel@tonic-gate 	}
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	fieldstart = p;
14870Sstevel@tonic-gate 	while (p < limit && !isspace(*p)) {
14880Sstevel@tonic-gate 		p++;		/* Scan the protocol name */
14890Sstevel@tonic-gate 	}
14900Sstevel@tonic-gate 	fieldlen = p - fieldstart + 1;		/* Include '\0' this time */
14910Sstevel@tonic-gate 	if (fieldlen > buflen - namelen - 1) {
14920Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
14930Sstevel@tonic-gate 	}
14940Sstevel@tonic-gate 	serv->s_proto = buffer + namelen + 1;
14950Sstevel@tonic-gate 	(void) memcpy(serv->s_proto, fieldstart, fieldlen - 1);
14960Sstevel@tonic-gate 	serv->s_proto[fieldlen - 1] = '\0';
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 	while (p < limit && isspace(*p)) {
14990Sstevel@tonic-gate 		p++;
15000Sstevel@tonic-gate 	}
15010Sstevel@tonic-gate 	/*
15020Sstevel@tonic-gate 	 * Although nss_files_XY_all calls us with # stripped,
15030Sstevel@tonic-gate 	 * we should be able to deal with it here in order to
15040Sstevel@tonic-gate 	 * be more useful.
15050Sstevel@tonic-gate 	 */
15060Sstevel@tonic-gate 	if (p >= limit || *p == '#') { /* no aliases, no problem */
15070Sstevel@tonic-gate 		char **ptr;
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate 		ptr = (char **)ROUND_UP(buffer + namelen + 1 + fieldlen,
15100Sstevel@tonic-gate 		    sizeof (char *));
15110Sstevel@tonic-gate 		if ((char *)ptr >= buffer + buflen) {
15120Sstevel@tonic-gate 			/* hope they don't try to peek in */
15130Sstevel@tonic-gate 			serv->s_aliases = 0;
15140Sstevel@tonic-gate 			return (NSS_STR_PARSE_ERANGE);
15150Sstevel@tonic-gate 		} else {
15160Sstevel@tonic-gate 			*ptr = 0;
15170Sstevel@tonic-gate 			serv->s_aliases = ptr;
15180Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
15190Sstevel@tonic-gate 		}
15200Sstevel@tonic-gate 	}
15210Sstevel@tonic-gate 	serv->s_aliases = _nss_netdb_aliases(p, (int)(lenstr - (p - instr)),
15220Sstevel@tonic-gate 	    buffer + namelen + 1 + fieldlen,
15230Sstevel@tonic-gate 	    (int)(buflen - namelen - 1 - fieldlen));
15240Sstevel@tonic-gate 	return (NSS_STR_PARSE_SUCCESS);
15250Sstevel@tonic-gate }
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate /*
15280Sstevel@tonic-gate  * Part III: All `n sundry routines that are useful only in this
15290Sstevel@tonic-gate  * module. In the interest of keeping this source file shorter,
15300Sstevel@tonic-gate  * we would create them a new module only if the linker allowed
15310Sstevel@tonic-gate  * "library-static" functions.
15320Sstevel@tonic-gate  *
15330Sstevel@tonic-gate  * Routines to order addresses based on local interfaces and netmasks,
15340Sstevel@tonic-gate  * to get and check reserved ports, and to get broadcast nets.
15350Sstevel@tonic-gate  */
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate union __v4v6addr {
15380Sstevel@tonic-gate 	struct in6_addr	in6;
15390Sstevel@tonic-gate 	struct in_addr	in4;
15400Sstevel@tonic-gate };
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate struct __ifaddr {
15430Sstevel@tonic-gate 	sa_family_t		af;
15440Sstevel@tonic-gate 	union __v4v6addr	addr;
15450Sstevel@tonic-gate 	union __v4v6addr	mask;
15460Sstevel@tonic-gate };
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate struct ifinfo {
15490Sstevel@tonic-gate 	int		count;
15500Sstevel@tonic-gate 	struct __ifaddr	*addresses;
15510Sstevel@tonic-gate };
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate typedef enum {ADDR_ONLINK = 0, ADDR_OFFLINK} addr_class_t;
15540Sstevel@tonic-gate #define	ADDR_NUMCLASSES	2
15550Sstevel@tonic-gate 
15560Sstevel@tonic-gate typedef enum {IF_ADDR, IF_MASK}	__ifaddr_type;
15570Sstevel@tonic-gate static int	__inet_ifassign(sa_family_t, struct __ifaddr *, __ifaddr_type,
15580Sstevel@tonic-gate 				void *);
15590Sstevel@tonic-gate int		__inet_address_is_local_af(void *, sa_family_t, void *);
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate #define	ifaf(index)	(localinfo->addresses[index].af)
15620Sstevel@tonic-gate #define	ifaddr4(index)	(localinfo->addresses[index].addr.in4)
15630Sstevel@tonic-gate #define	ifaddr6(index)	(localinfo->addresses[index].addr.in6)
15640Sstevel@tonic-gate #define	ifmask4(index)	(localinfo->addresses[index].mask.in4)
15650Sstevel@tonic-gate #define	ifmask6(index)	(localinfo->addresses[index].mask.in6)
15660Sstevel@tonic-gate #define	ifinfosize(n)	(sizeof (struct ifinfo) + (n)*sizeof (struct __ifaddr))
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate #define	lifraddrp(lifr)	((lifr.lifr_addr.ss_family == AF_INET6) ? \
15690Sstevel@tonic-gate 	(void *)&((struct sockaddr_in6 *)&lifr.lifr_addr)->sin6_addr : \
15700Sstevel@tonic-gate 	(void *)&((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr)
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate #define	ifassign(lifr, index, type) \
15730Sstevel@tonic-gate 			__inet_ifassign(lifr.lifr_addr.ss_family, \
15740Sstevel@tonic-gate 				&localinfo->addresses[index], type, \
15750Sstevel@tonic-gate 				lifraddrp(lifr))
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate /*
15780Sstevel@tonic-gate  * The number of nanoseconds the order_haddrlist_inet() function waits
15790Sstevel@tonic-gate  * to retreive IP interface information.  The default is five minutes.
15800Sstevel@tonic-gate  */
15810Sstevel@tonic-gate #define	IFINFOTIMEOUT	((hrtime_t)300 * NANOSEC)
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate /*
15840Sstevel@tonic-gate  * Sort the addresses in haddrlist.  Since the sorting algorithms are
15850Sstevel@tonic-gate  * address-family specific, the work is done in the address-family
15860Sstevel@tonic-gate  * specific order_haddrlist_<family> functions.
15870Sstevel@tonic-gate  *
15880Sstevel@tonic-gate  * Do not sort addresses if SORT_ADDRS variable is set to NO or FALSE
15890Sstevel@tonic-gate  * in the configuration file /etc/default/nss. This is useful in case
15900Sstevel@tonic-gate  * the order of addresses returned by the nameserver needs to be
15910Sstevel@tonic-gate  * maintained. (DNS round robin feature is one example)
15920Sstevel@tonic-gate  */
15930Sstevel@tonic-gate void
order_haddrlist_af(sa_family_t af,char ** haddrlist)15940Sstevel@tonic-gate order_haddrlist_af(sa_family_t af, char **haddrlist)
15950Sstevel@tonic-gate {
15960Sstevel@tonic-gate 	size_t			addrcount;
15970Sstevel@tonic-gate 	char			**addrptr;
15980Sstevel@tonic-gate 	static boolean_t	checksortcfg = B_TRUE;
15990Sstevel@tonic-gate 	static boolean_t	nosort = B_FALSE;
16000Sstevel@tonic-gate 	static mutex_t		checksortcfg_lock = DEFAULTMUTEX;
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 	if (haddrlist == NULL)
16030Sstevel@tonic-gate 		return;
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 	/*
16060Sstevel@tonic-gate 	 * Check if SORT_ADDRS is set to NO or FALSE in the configuration
16070Sstevel@tonic-gate 	 * file.  We do not have to sort addresses in that case.
16080Sstevel@tonic-gate 	 */
16090Sstevel@tonic-gate 	(void) mutex_lock(&checksortcfg_lock);
16100Sstevel@tonic-gate 	if (checksortcfg == B_TRUE) {
16110Sstevel@tonic-gate 		checksortcfg = B_FALSE;
16120Sstevel@tonic-gate 		nosort = _read_nsw_file();
16130Sstevel@tonic-gate 	}
16140Sstevel@tonic-gate 	(void) mutex_unlock(&checksortcfg_lock);
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate 	if (nosort)
16170Sstevel@tonic-gate 		return;
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate 	/* Count the addresses to sort */
16200Sstevel@tonic-gate 	addrcount = 0;
16210Sstevel@tonic-gate 	for (addrptr = haddrlist; *addrptr != NULL; addrptr++)
16220Sstevel@tonic-gate 		addrcount++;
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 	/*
16250Sstevel@tonic-gate 	 * If there's only one address or no addresses to sort, then
16260Sstevel@tonic-gate 	 * there's nothing for us to do.
16270Sstevel@tonic-gate 	 */
16280Sstevel@tonic-gate 	if (addrcount <= 1)
16290Sstevel@tonic-gate 		return;
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 	/* Call the address-family specific sorting functions. */
16320Sstevel@tonic-gate 	switch (af) {
16330Sstevel@tonic-gate 	case AF_INET:
16340Sstevel@tonic-gate 		order_haddrlist_inet(haddrlist, addrcount);
16350Sstevel@tonic-gate 		break;
16360Sstevel@tonic-gate 	case AF_INET6:
16370Sstevel@tonic-gate 		order_haddrlist_inet6(haddrlist, addrcount);
16380Sstevel@tonic-gate 		break;
16390Sstevel@tonic-gate 	default:
16400Sstevel@tonic-gate 		break;
16410Sstevel@tonic-gate 	}
16420Sstevel@tonic-gate }
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate /*
16450Sstevel@tonic-gate  * Move any local (on-link) addresses toward the beginning of haddrlist.
16460Sstevel@tonic-gate  * The order within these two classes is preserved.
16470Sstevel@tonic-gate  *
16480Sstevel@tonic-gate  * The interface list is retrieved no more often than every
16490Sstevel@tonic-gate  * IFINFOTIMEOUT nanoseconds. Access to the interface list is
16500Sstevel@tonic-gate  * protected by an RW lock.
16510Sstevel@tonic-gate  *
16520Sstevel@tonic-gate  * If this function encounters an error, haddrlist is unaltered.
16530Sstevel@tonic-gate  */
16540Sstevel@tonic-gate static void
order_haddrlist_inet(char ** haddrlist,size_t addrcount)16550Sstevel@tonic-gate order_haddrlist_inet(char **haddrlist, size_t addrcount)
16560Sstevel@tonic-gate {
16570Sstevel@tonic-gate 	static struct	ifinfo *localinfo = NULL;
16580Sstevel@tonic-gate 	static hrtime_t	then = 0; /* the last time localinfo was updated */
16590Sstevel@tonic-gate 	hrtime_t	now;
16600Sstevel@tonic-gate 	static rwlock_t	localinfo_lock = DEFAULTRWLOCK;
16610Sstevel@tonic-gate 	uint8_t		*sortbuf;
16620Sstevel@tonic-gate 	size_t		sortbuf_size;
16630Sstevel@tonic-gate 	struct in_addr	**inaddrlist = (struct in_addr **)haddrlist;
16640Sstevel@tonic-gate 	struct in_addr	**sorted;
16650Sstevel@tonic-gate 	struct in_addr	**classnext[ADDR_NUMCLASSES];
16660Sstevel@tonic-gate 	uint_t		classcount[ADDR_NUMCLASSES];
16670Sstevel@tonic-gate 	addr_class_t	*sortclass;
16680Sstevel@tonic-gate 	int		i;
16690Sstevel@tonic-gate 	int		rc;
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 	/*
16730Sstevel@tonic-gate 	 * The classes in the sortclass array correspond to the class
16740Sstevel@tonic-gate 	 * of the address in the haddrlist list of the same index.
16750Sstevel@tonic-gate 	 * The classes are:
16760Sstevel@tonic-gate 	 *
16770Sstevel@tonic-gate 	 * ADDR_ONLINK	on-link address
16780Sstevel@tonic-gate 	 * ADDR_OFFLINK	off-link address
16790Sstevel@tonic-gate 	 */
16800Sstevel@tonic-gate 	sortbuf_size = addrcount *
16810Sstevel@tonic-gate 	    (sizeof (struct in_addr *) + sizeof (addr_class_t));
16820Sstevel@tonic-gate 	if ((sortbuf = malloc(sortbuf_size)) == NULL)
16830Sstevel@tonic-gate 		return;
1684132Srobinson 	/* LINTED pointer cast */
16850Sstevel@tonic-gate 	sorted = (struct in_addr **)sortbuf;
1686132Srobinson 	/* LINTED pointer cast */
16870Sstevel@tonic-gate 	sortclass = (addr_class_t *)(sortbuf +
16880Sstevel@tonic-gate 	    (addrcount * sizeof (struct in_addr *)));
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 	/*
16910Sstevel@tonic-gate 	 * Get a read lock, and check if the interface information
16920Sstevel@tonic-gate 	 * is too old.
16930Sstevel@tonic-gate 	 */
16940Sstevel@tonic-gate 	(void) rw_rdlock(&localinfo_lock);
16950Sstevel@tonic-gate 	now = gethrtime();
16960Sstevel@tonic-gate 	if (localinfo == NULL || ((now - then) > IFINFOTIMEOUT)) {
16970Sstevel@tonic-gate 		/* Need to update I/F info. Upgrade to write lock. */
16980Sstevel@tonic-gate 		(void) rw_unlock(&localinfo_lock);
16990Sstevel@tonic-gate 		(void) rw_wrlock(&localinfo_lock);
17000Sstevel@tonic-gate 		/*
17010Sstevel@tonic-gate 		 * Another thread might have updated "then" between
17020Sstevel@tonic-gate 		 * the rw_unlock() and rw_wrlock() calls above, so
17030Sstevel@tonic-gate 		 * re-check the timeout.
17040Sstevel@tonic-gate 		 */
17050Sstevel@tonic-gate 		if (localinfo == NULL || ((now - then) > IFINFOTIMEOUT)) {
17060Sstevel@tonic-gate 			if (localinfo != NULL)
17070Sstevel@tonic-gate 				free(localinfo);
17080Sstevel@tonic-gate 			if ((localinfo = get_local_info()) == NULL) {
17090Sstevel@tonic-gate 				(void) rw_unlock(&localinfo_lock);
17100Sstevel@tonic-gate 				free(sortbuf);
17110Sstevel@tonic-gate 				return;
17120Sstevel@tonic-gate 			}
17130Sstevel@tonic-gate 			then = now;
17140Sstevel@tonic-gate 		}
17150Sstevel@tonic-gate 		/* Downgrade to read lock */
17160Sstevel@tonic-gate 		(void) rw_unlock(&localinfo_lock);
17170Sstevel@tonic-gate 		(void) rw_rdlock(&localinfo_lock);
17180Sstevel@tonic-gate 		/*
17190Sstevel@tonic-gate 		 * Another thread may have updated the I/F info,
17200Sstevel@tonic-gate 		 * so verify that the 'localinfo' pointer still
17210Sstevel@tonic-gate 		 * is non-NULL.
17220Sstevel@tonic-gate 		 */
17230Sstevel@tonic-gate 		if (localinfo == NULL) {
17240Sstevel@tonic-gate 			(void) rw_unlock(&localinfo_lock);
17250Sstevel@tonic-gate 			free(sortbuf);
17260Sstevel@tonic-gate 			return;
17270Sstevel@tonic-gate 		}
17280Sstevel@tonic-gate 	}
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 	/*
17310Sstevel@tonic-gate 	 * Classify the addresses.  We also maintain the classcount
17320Sstevel@tonic-gate 	 * array to keep track of the number of addresses in each
17330Sstevel@tonic-gate 	 * class.
17340Sstevel@tonic-gate 	 */
1735132Srobinson 	(void) memset(classcount, 0, sizeof (classcount));
17360Sstevel@tonic-gate 	for (i = 0; i < addrcount; i++) {
17370Sstevel@tonic-gate 		if (__inet_address_is_local_af(localinfo, AF_INET,
17380Sstevel@tonic-gate 		    inaddrlist[i]))
17390Sstevel@tonic-gate 			sortclass[i] = ADDR_ONLINK;
17400Sstevel@tonic-gate 		else
17410Sstevel@tonic-gate 			sortclass[i] = ADDR_OFFLINK;
17420Sstevel@tonic-gate 		classcount[sortclass[i]]++;
17430Sstevel@tonic-gate 	}
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate 	/* Don't need the interface list anymore in this call */
17460Sstevel@tonic-gate 	(void) rw_unlock(&localinfo_lock);
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 	/*
17490Sstevel@tonic-gate 	 * Each element in the classnext array points to the next
17500Sstevel@tonic-gate 	 * element for that class in the sorted address list. 'rc' is
17510Sstevel@tonic-gate 	 * the running count of elements as we sum the class
17520Sstevel@tonic-gate 	 * sub-totals.
17530Sstevel@tonic-gate 	 */
17540Sstevel@tonic-gate 	for (rc = 0, i = 0; i < ADDR_NUMCLASSES; i++) {
17550Sstevel@tonic-gate 		classnext[i] = &sorted[rc];
17560Sstevel@tonic-gate 		rc += classcount[i];
17570Sstevel@tonic-gate 	}
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate 	/* Now for the actual rearrangement of the addresses */
17600Sstevel@tonic-gate 	for (i = 0; i < addrcount; i++) {
17610Sstevel@tonic-gate 		*(classnext[sortclass[i]]) = inaddrlist[i];
17620Sstevel@tonic-gate 		classnext[sortclass[i]]++;
17630Sstevel@tonic-gate 	}
17640Sstevel@tonic-gate 
17650Sstevel@tonic-gate 	/* Copy the sorted list to inaddrlist */
17660Sstevel@tonic-gate 	(void) memcpy(inaddrlist, sorted,
17670Sstevel@tonic-gate 	    addrcount * sizeof (struct in_addr *));
17680Sstevel@tonic-gate 	free(sortbuf);
17690Sstevel@tonic-gate }
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate /*
17720Sstevel@tonic-gate  * This function implements the IPv6 Default Address Selection's
17730Sstevel@tonic-gate  * destination address ordering mechanism.  The algorithm is described
17740Sstevel@tonic-gate  * in getaddrinfo(3SOCKET).
17750Sstevel@tonic-gate  */
17760Sstevel@tonic-gate static void
order_haddrlist_inet6(char ** haddrlist,size_t addrcount)17770Sstevel@tonic-gate order_haddrlist_inet6(char **haddrlist, size_t addrcount)
17780Sstevel@tonic-gate {
17790Sstevel@tonic-gate 	struct dstinforeq *dinfo, *dinfoptr;
17800Sstevel@tonic-gate 	struct in6_addr **in6addrlist = (struct in6_addr **)haddrlist;
17810Sstevel@tonic-gate 	struct in6_addr	**in6addr;
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate 	if ((dinfo = calloc(addrcount, sizeof (struct dstinforeq))) == NULL)
17840Sstevel@tonic-gate 		return;
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 	/* Initialize the dstinfo array we'll use for SIOCGDSTINFO */
17870Sstevel@tonic-gate 	dinfoptr = dinfo;
17880Sstevel@tonic-gate 	for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) {
17890Sstevel@tonic-gate 		dinfoptr->dir_daddr = **in6addr;
17900Sstevel@tonic-gate 		dinfoptr++;
17910Sstevel@tonic-gate 	}
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 	if (nss_strioctl(AF_INET6, SIOCGDSTINFO, dinfo,
17940Sstevel@tonic-gate 	    addrcount * sizeof (struct dstinforeq)) < 0) {
17950Sstevel@tonic-gate 		free(dinfo);
17960Sstevel@tonic-gate 		return;
17970Sstevel@tonic-gate 	}
17980Sstevel@tonic-gate 
17990Sstevel@tonic-gate 	/* Sort the dinfo array */
18000Sstevel@tonic-gate 	qsort(dinfo, addrcount, sizeof (struct dstinforeq), dstcmp);
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 	/* Copy the addresses back into in6addrlist */
18030Sstevel@tonic-gate 	dinfoptr = dinfo;
18040Sstevel@tonic-gate 	for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) {
18050Sstevel@tonic-gate 		**in6addr = dinfoptr->dir_daddr;
18060Sstevel@tonic-gate 		dinfoptr++;
18070Sstevel@tonic-gate 	}
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 	free(dinfo);
18100Sstevel@tonic-gate }
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate /*
18130Sstevel@tonic-gate  * Determine number of leading bits that are common between two addresses.
18140Sstevel@tonic-gate  * Only consider bits which fall within the prefix length plen.
18150Sstevel@tonic-gate  */
18160Sstevel@tonic-gate static uint_t
ip_addr_commonbits_v6(const in6_addr_t * a1,const in6_addr_t * a2)18170Sstevel@tonic-gate ip_addr_commonbits_v6(const in6_addr_t *a1, const in6_addr_t *a2)
18180Sstevel@tonic-gate {
18190Sstevel@tonic-gate 	uint_t		bits;
18200Sstevel@tonic-gate 	uint_t		i;
18210Sstevel@tonic-gate 	uint32_t	diff;	/* Bits that differ */
18220Sstevel@tonic-gate 
18230Sstevel@tonic-gate 	for (i = 0; i < 4; i++) {
18240Sstevel@tonic-gate 		if (a1->_S6_un._S6_u32[i] != a2->_S6_un._S6_u32[i])
18250Sstevel@tonic-gate 			break;
18260Sstevel@tonic-gate 	}
18270Sstevel@tonic-gate 	bits = i * 32;
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 	if (bits == IPV6_ABITS)
18300Sstevel@tonic-gate 		return (IPV6_ABITS);
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate 	/*
18330Sstevel@tonic-gate 	 * Find number of leading common bits in the word which might
18340Sstevel@tonic-gate 	 * have some common bits by searching for the first one from the left
18350Sstevel@tonic-gate 	 * in the xor of the two addresses.
18360Sstevel@tonic-gate 	 */
18370Sstevel@tonic-gate 	diff = ntohl(a1->_S6_un._S6_u32[i] ^ a2->_S6_un._S6_u32[i]);
18380Sstevel@tonic-gate 	if (diff & 0xffff0000ul)
18390Sstevel@tonic-gate 		diff >>= 16;
18400Sstevel@tonic-gate 	else
18410Sstevel@tonic-gate 		bits += 16;
18420Sstevel@tonic-gate 	if (diff & 0xff00)
18430Sstevel@tonic-gate 		diff >>= 8;
18440Sstevel@tonic-gate 	else
18450Sstevel@tonic-gate 		bits += 8;
18460Sstevel@tonic-gate 	if (diff & 0xf0)
18470Sstevel@tonic-gate 		diff >>= 4;
18480Sstevel@tonic-gate 	else
18490Sstevel@tonic-gate 		bits += 4;
18500Sstevel@tonic-gate 	if (diff & 0xc)
18510Sstevel@tonic-gate 		diff >>= 2;
18520Sstevel@tonic-gate 	else
18530Sstevel@tonic-gate 		bits += 2;
18540Sstevel@tonic-gate 	if (!(diff & 2))
18550Sstevel@tonic-gate 		bits++;
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 	/*
18580Sstevel@tonic-gate 	 * We don't need to shift and check for the last bit.  The
18590Sstevel@tonic-gate 	 * check for IPV6_ABITS above would have caught that.
18600Sstevel@tonic-gate 	 */
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 	return (bits);
18630Sstevel@tonic-gate }
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 
18660Sstevel@tonic-gate /*
18670Sstevel@tonic-gate  * The following group of functions named rule_*() are individual
18680Sstevel@tonic-gate  * sorting rules for the AF_INET6 address sorting algorithm.  The
18690Sstevel@tonic-gate  * functions compare two addresses (described by two dstinforeq
18700Sstevel@tonic-gate  * structures), and determines if one is "greater" than the other, or
18710Sstevel@tonic-gate  * if the two are equal according to that rule.
18720Sstevel@tonic-gate  */
18730Sstevel@tonic-gate typedef	int (*rulef_t)(const struct dstinforeq *, const struct dstinforeq *);
18740Sstevel@tonic-gate 
18750Sstevel@tonic-gate /*
18760Sstevel@tonic-gate  * These values of these constants are no accident.  Since qsort()
18770Sstevel@tonic-gate  * implements the AF_INET6 address sorting, the comparison function
18780Sstevel@tonic-gate  * must return an integer less than, equal to, or greater than zero to
18790Sstevel@tonic-gate  * indicate if the first address is considered "less than", "equal
18800Sstevel@tonic-gate  * to", or "greater than" the second one.  Since we want the best
18810Sstevel@tonic-gate  * addresses first on the list, "less than" is considered preferrable.
18820Sstevel@tonic-gate  */
18830Sstevel@tonic-gate #define	RULE_PREFER_DA	-1
18840Sstevel@tonic-gate #define	RULE_PREFER_DB	1
18850Sstevel@tonic-gate #define	RULE_EQUAL	0
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate /* Prefer the addresses that is reachable. */
18880Sstevel@tonic-gate static int
rule_reachable(const struct dstinforeq * da,const struct dstinforeq * db)18890Sstevel@tonic-gate rule_reachable(const struct dstinforeq *da, const struct dstinforeq *db)
18900Sstevel@tonic-gate {
18910Sstevel@tonic-gate 	if (da->dir_dreachable == db->dir_dreachable)
18920Sstevel@tonic-gate 		return (RULE_EQUAL);
18930Sstevel@tonic-gate 	if (da->dir_dreachable)
18940Sstevel@tonic-gate 		return (RULE_PREFER_DA);
18950Sstevel@tonic-gate 	return (RULE_PREFER_DB);
18960Sstevel@tonic-gate }
18970Sstevel@tonic-gate 
18980Sstevel@tonic-gate /* Prefer the address whose scope matches that of its source address. */
18990Sstevel@tonic-gate static int
rule_matchscope(const struct dstinforeq * da,const struct dstinforeq * db)19000Sstevel@tonic-gate rule_matchscope(const struct dstinforeq *da, const struct dstinforeq *db)
19010Sstevel@tonic-gate {
19020Sstevel@tonic-gate 	boolean_t da_scope_match, db_scope_match;
19030Sstevel@tonic-gate 
19040Sstevel@tonic-gate 	da_scope_match = da->dir_dscope == da->dir_sscope;
19050Sstevel@tonic-gate 	db_scope_match = db->dir_dscope == db->dir_sscope;
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 	if (da_scope_match == db_scope_match)
19080Sstevel@tonic-gate 		return (RULE_EQUAL);
19090Sstevel@tonic-gate 	if (da_scope_match)
19100Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19110Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19120Sstevel@tonic-gate }
19130Sstevel@tonic-gate 
19140Sstevel@tonic-gate /* Avoid the address with the link local source address. */
19150Sstevel@tonic-gate static int
rule_avoidlinklocal(const struct dstinforeq * da,const struct dstinforeq * db)19160Sstevel@tonic-gate rule_avoidlinklocal(const struct dstinforeq *da, const struct dstinforeq *db)
19170Sstevel@tonic-gate {
19180Sstevel@tonic-gate 	if (da->dir_sscope == IP6_SCOPE_LINKLOCAL &&
19190Sstevel@tonic-gate 	    da->dir_dscope != IP6_SCOPE_LINKLOCAL &&
19200Sstevel@tonic-gate 	    db->dir_sscope != IP6_SCOPE_LINKLOCAL)
19210Sstevel@tonic-gate 		return (RULE_PREFER_DB);
19220Sstevel@tonic-gate 	if (db->dir_sscope == IP6_SCOPE_LINKLOCAL &&
19230Sstevel@tonic-gate 	    db->dir_dscope != IP6_SCOPE_LINKLOCAL &&
19240Sstevel@tonic-gate 	    da->dir_sscope != IP6_SCOPE_LINKLOCAL)
19250Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19260Sstevel@tonic-gate 	return (RULE_EQUAL);
19270Sstevel@tonic-gate }
19280Sstevel@tonic-gate 
19290Sstevel@tonic-gate /* Prefer the address whose source address isn't deprecated. */
19300Sstevel@tonic-gate static int
rule_deprecated(const struct dstinforeq * da,const struct dstinforeq * db)19310Sstevel@tonic-gate rule_deprecated(const struct dstinforeq *da, const struct dstinforeq *db)
19320Sstevel@tonic-gate {
19330Sstevel@tonic-gate 	if (da->dir_sdeprecated == db->dir_sdeprecated)
19340Sstevel@tonic-gate 		return (RULE_EQUAL);
19350Sstevel@tonic-gate 	if (db->dir_sdeprecated)
19360Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19370Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19380Sstevel@tonic-gate }
19390Sstevel@tonic-gate 
19400Sstevel@tonic-gate /* Prefer the address whose label matches that of its source address. */
19410Sstevel@tonic-gate static int
rule_label(const struct dstinforeq * da,const struct dstinforeq * db)19420Sstevel@tonic-gate rule_label(const struct dstinforeq *da, const struct dstinforeq *db)
19430Sstevel@tonic-gate {
19440Sstevel@tonic-gate 	if (da->dir_labelmatch == db->dir_labelmatch)
19450Sstevel@tonic-gate 		return (RULE_EQUAL);
19460Sstevel@tonic-gate 	if (da->dir_labelmatch)
19470Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19480Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19490Sstevel@tonic-gate }
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate /* Prefer the address with the higher precedence. */
19520Sstevel@tonic-gate static int
rule_precedence(const struct dstinforeq * da,const struct dstinforeq * db)19530Sstevel@tonic-gate rule_precedence(const struct dstinforeq *da, const struct dstinforeq *db)
19540Sstevel@tonic-gate {
19550Sstevel@tonic-gate 	if (da->dir_precedence == db->dir_precedence)
19560Sstevel@tonic-gate 		return (RULE_EQUAL);
19570Sstevel@tonic-gate 	if (da->dir_precedence > db->dir_precedence)
19580Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19590Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19600Sstevel@tonic-gate }
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate /* Prefer the address whose output interface isn't an IP tunnel */
19630Sstevel@tonic-gate static int
rule_native(const struct dstinforeq * da,const struct dstinforeq * db)19640Sstevel@tonic-gate rule_native(const struct dstinforeq *da, const struct dstinforeq *db)
19650Sstevel@tonic-gate {
19660Sstevel@tonic-gate 	boolean_t isatun, isbtun;
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate 	/* Get the common case out of the way early */
19690Sstevel@tonic-gate 	if (da->dir_dmactype == db->dir_dmactype)
19700Sstevel@tonic-gate 		return (RULE_EQUAL);
19710Sstevel@tonic-gate 
19720Sstevel@tonic-gate 	isatun = da->dir_dmactype == DL_IPV4 || da->dir_dmactype == DL_IPV6;
19730Sstevel@tonic-gate 	isbtun = db->dir_dmactype == DL_IPV4 || db->dir_dmactype == DL_IPV6;
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate 	if (isatun == isbtun)
19760Sstevel@tonic-gate 		return (RULE_EQUAL);
19770Sstevel@tonic-gate 	if (isbtun)
19780Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19790Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19800Sstevel@tonic-gate }
19810Sstevel@tonic-gate 
19820Sstevel@tonic-gate /* Prefer the address with the smaller scope. */
19830Sstevel@tonic-gate static int
rule_scope(const struct dstinforeq * da,const struct dstinforeq * db)19840Sstevel@tonic-gate rule_scope(const struct dstinforeq *da, const struct dstinforeq *db)
19850Sstevel@tonic-gate {
19860Sstevel@tonic-gate 	if (da->dir_dscope == db->dir_dscope)
19870Sstevel@tonic-gate 		return (RULE_EQUAL);
19880Sstevel@tonic-gate 	if (da->dir_dscope < db->dir_dscope)
19890Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19900Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19910Sstevel@tonic-gate }
19920Sstevel@tonic-gate 
19930Sstevel@tonic-gate /*
19940Sstevel@tonic-gate  * Prefer the address that has the most leading bits in common with its
19950Sstevel@tonic-gate  * source address.
19960Sstevel@tonic-gate  */
19970Sstevel@tonic-gate static int
rule_prefix(const struct dstinforeq * da,const struct dstinforeq * db)19980Sstevel@tonic-gate rule_prefix(const struct dstinforeq *da, const struct dstinforeq *db)
19990Sstevel@tonic-gate {
20000Sstevel@tonic-gate 	uint_t da_commonbits, db_commonbits;
20010Sstevel@tonic-gate 	boolean_t da_isipv4, db_isipv4;
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate 	da_isipv4 = IN6_IS_ADDR_V4MAPPED(&da->dir_daddr);
20040Sstevel@tonic-gate 	db_isipv4 = IN6_IS_ADDR_V4MAPPED(&db->dir_daddr);
20050Sstevel@tonic-gate 
20060Sstevel@tonic-gate 	/*
20070Sstevel@tonic-gate 	 * At this point, the order doesn't matter if the two addresses
20080Sstevel@tonic-gate 	 * aren't of the same address family.
20090Sstevel@tonic-gate 	 */
20100Sstevel@tonic-gate 	if (da_isipv4 != db_isipv4)
20110Sstevel@tonic-gate 		return (RULE_EQUAL);
20120Sstevel@tonic-gate 
20130Sstevel@tonic-gate 	da_commonbits = ip_addr_commonbits_v6(&da->dir_daddr, &da->dir_saddr);
20140Sstevel@tonic-gate 	db_commonbits = ip_addr_commonbits_v6(&db->dir_daddr, &db->dir_saddr);
20150Sstevel@tonic-gate 
20160Sstevel@tonic-gate 	if (da_commonbits > db_commonbits)
20170Sstevel@tonic-gate 		return (RULE_PREFER_DA);
20180Sstevel@tonic-gate 	if (da_commonbits < db_commonbits)
20190Sstevel@tonic-gate 		return (RULE_PREFER_DB);
20200Sstevel@tonic-gate 	return (RULE_EQUAL);
20210Sstevel@tonic-gate }
20220Sstevel@tonic-gate 
20230Sstevel@tonic-gate /*
20240Sstevel@tonic-gate  * This is the function passed to qsort() that does the AF_INET6
20250Sstevel@tonic-gate  * address comparisons.  It compares two addresses using a list of
20260Sstevel@tonic-gate  * rules.  The rules are applied in order until one prefers one
20270Sstevel@tonic-gate  * address over the other.
20280Sstevel@tonic-gate  */
20290Sstevel@tonic-gate static int
dstcmp(const void * da,const void * db)20300Sstevel@tonic-gate dstcmp(const void *da, const void *db)
20310Sstevel@tonic-gate {
20320Sstevel@tonic-gate 	int index, result;
20330Sstevel@tonic-gate 	rulef_t rules[] = {
2034*7752SMichen.Chang@Sun.COM 	    rule_reachable,
2035*7752SMichen.Chang@Sun.COM 	    rule_matchscope,
2036*7752SMichen.Chang@Sun.COM 	    rule_avoidlinklocal,
2037*7752SMichen.Chang@Sun.COM 	    rule_deprecated,
2038*7752SMichen.Chang@Sun.COM 	    rule_label,
2039*7752SMichen.Chang@Sun.COM 	    rule_precedence,
2040*7752SMichen.Chang@Sun.COM 	    rule_native,
2041*7752SMichen.Chang@Sun.COM 	    rule_scope,
2042*7752SMichen.Chang@Sun.COM 	    rule_prefix,
2043*7752SMichen.Chang@Sun.COM 	    NULL
20440Sstevel@tonic-gate 	};
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 	result = 0;
20470Sstevel@tonic-gate 	for (index = 0; rules[index] != NULL; index++) {
20480Sstevel@tonic-gate 		result = (rules[index])(da, db);
20490Sstevel@tonic-gate 		if (result != RULE_EQUAL)
20500Sstevel@tonic-gate 			break;
20510Sstevel@tonic-gate 	}
20520Sstevel@tonic-gate 
20530Sstevel@tonic-gate 	return (result);
20540Sstevel@tonic-gate }
20550Sstevel@tonic-gate 
20560Sstevel@tonic-gate /*
20570Sstevel@tonic-gate  * Given haddrlist and a port number, mallocs and populates a new
20580Sstevel@tonic-gate  * nd_addrlist.  The new nd_addrlist maintains the order of the addresses
20590Sstevel@tonic-gate  * in haddrlist, which have already been sorted by order_haddrlist_inet()
20600Sstevel@tonic-gate  * or order_haddrlist_inet6().  For IPv6 this function filters out
20610Sstevel@tonic-gate  * IPv4-mapped IPv6 addresses.
20620Sstevel@tonic-gate  */
20630Sstevel@tonic-gate int
hent2ndaddr(int af,char ** haddrlist,int * servp,struct nd_addrlist ** nd_alist)20640Sstevel@tonic-gate hent2ndaddr(int af, char **haddrlist, int *servp, struct nd_addrlist **nd_alist)
20650Sstevel@tonic-gate {
20660Sstevel@tonic-gate 	struct nd_addrlist	*result;
20670Sstevel@tonic-gate 	int			num;
20680Sstevel@tonic-gate 	struct netbuf		*na;
20690Sstevel@tonic-gate 	struct sockaddr_in	*sinbuf, *sin;
20700Sstevel@tonic-gate 	struct sockaddr_in6	*sin6buf, *sin6;
20710Sstevel@tonic-gate 	struct in_addr		**inaddr, **inaddrlist;
20720Sstevel@tonic-gate 	struct in6_addr		**in6addr, **in6addrlist;
20730Sstevel@tonic-gate 
20740Sstevel@tonic-gate 	/* Address count */
20750Sstevel@tonic-gate 	num = 0;
20760Sstevel@tonic-gate 	if (af == AF_INET6) {
20770Sstevel@tonic-gate 		in6addrlist = (struct in6_addr **)haddrlist;
20780Sstevel@tonic-gate 
20790Sstevel@tonic-gate 		/*
20800Sstevel@tonic-gate 		 * Exclude IPv4-mapped IPv6 addresses from the count, as
20810Sstevel@tonic-gate 		 * these are not included in the nd_addrlist we return.
20820Sstevel@tonic-gate 		 */
20830Sstevel@tonic-gate 		for (in6addr = in6addrlist; *in6addr != NULL; in6addr++)
20840Sstevel@tonic-gate 			if (!IN6_IS_ADDR_V4MAPPED(*in6addr))
20850Sstevel@tonic-gate 				num++;
20860Sstevel@tonic-gate 	} else {
20870Sstevel@tonic-gate 		inaddrlist = (struct in_addr **)haddrlist;
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate 		for (inaddr = inaddrlist; *inaddr != NULL; inaddr++)
20900Sstevel@tonic-gate 			num++;
20910Sstevel@tonic-gate 	}
20920Sstevel@tonic-gate 	if (num == 0)
20930Sstevel@tonic-gate 		return (ND_NOHOST);
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate 	result = malloc(sizeof (struct nd_addrlist));
20960Sstevel@tonic-gate 	if (result == 0)
20970Sstevel@tonic-gate 		return (ND_NOMEM);
20980Sstevel@tonic-gate 
20990Sstevel@tonic-gate 	result->n_cnt = num;
21000Sstevel@tonic-gate 	result->n_addrs = calloc(num, sizeof (struct netbuf));
21010Sstevel@tonic-gate 	if (result->n_addrs == 0) {
21020Sstevel@tonic-gate 		free(result);
21030Sstevel@tonic-gate 		return (ND_NOMEM);
21040Sstevel@tonic-gate 	}
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 	na = result->n_addrs;
21070Sstevel@tonic-gate 	if (af == AF_INET) {
21080Sstevel@tonic-gate 		sinbuf = calloc(num, sizeof (struct sockaddr_in));
21090Sstevel@tonic-gate 		if (sinbuf == NULL) {
21100Sstevel@tonic-gate 			free(result->n_addrs);
21110Sstevel@tonic-gate 			free(result);
21120Sstevel@tonic-gate 			return (ND_NOMEM);
21130Sstevel@tonic-gate 		}
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 		sin = sinbuf;
21160Sstevel@tonic-gate 		for (inaddr = inaddrlist; *inaddr != NULL; inaddr++) {
21170Sstevel@tonic-gate 			na->len = na->maxlen = sizeof (struct sockaddr_in);
21180Sstevel@tonic-gate 			na->buf = (char *)sin;
21190Sstevel@tonic-gate 			sin->sin_family = AF_INET;
21200Sstevel@tonic-gate 			sin->sin_addr = **inaddr;
21210Sstevel@tonic-gate 			sin->sin_port = *servp;
21220Sstevel@tonic-gate 			na++;
21230Sstevel@tonic-gate 			sin++;
21240Sstevel@tonic-gate 		}
21250Sstevel@tonic-gate 	} else if (af == AF_INET6) {
21260Sstevel@tonic-gate 		sin6buf = calloc(num, sizeof (struct sockaddr_in6));
21270Sstevel@tonic-gate 		if (sin6buf == NULL) {
21280Sstevel@tonic-gate 			free(result->n_addrs);
21290Sstevel@tonic-gate 			free(result);
21300Sstevel@tonic-gate 			return (ND_NOMEM);
21310Sstevel@tonic-gate 		}
21320Sstevel@tonic-gate 
21330Sstevel@tonic-gate 		sin6 = sin6buf;
21340Sstevel@tonic-gate 		for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) {
21350Sstevel@tonic-gate 			if (IN6_IS_ADDR_V4MAPPED(*in6addr))
21360Sstevel@tonic-gate 				continue;
21370Sstevel@tonic-gate 
21380Sstevel@tonic-gate 			na->len = na->maxlen = sizeof (struct sockaddr_in6);
21390Sstevel@tonic-gate 			na->buf = (char *)sin6;
21400Sstevel@tonic-gate 			sin6->sin6_family = AF_INET6;
21410Sstevel@tonic-gate 			sin6->sin6_addr = **in6addr;
21420Sstevel@tonic-gate 			sin6->sin6_port = *servp;
21430Sstevel@tonic-gate 			na++;
21440Sstevel@tonic-gate 			sin6++;
21450Sstevel@tonic-gate 		}
21460Sstevel@tonic-gate 	}
21470Sstevel@tonic-gate 	*(nd_alist) = result;
21480Sstevel@tonic-gate 	return (ND_OK);
21490Sstevel@tonic-gate }
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate /*
21520Sstevel@tonic-gate  * Given a hostent and a servent, mallocs and populates
21530Sstevel@tonic-gate  * a new nd_hostservlist with host and service names.
21540Sstevel@tonic-gate  *
21550Sstevel@tonic-gate  * We could be passed in a NULL servent, in which case stringify port.
21560Sstevel@tonic-gate  */
21570Sstevel@tonic-gate int
hsents2ndhostservs(struct hostent * he,struct servent * se,ushort_t port,struct nd_hostservlist ** hslist)21580Sstevel@tonic-gate hsents2ndhostservs(struct hostent *he, struct servent *se,
21590Sstevel@tonic-gate     ushort_t port, struct nd_hostservlist **hslist)
21600Sstevel@tonic-gate {
21610Sstevel@tonic-gate 	struct	nd_hostservlist *result;
21620Sstevel@tonic-gate 	struct	nd_hostserv *hs;
21630Sstevel@tonic-gate 	int	hosts, servs, i, j;
21640Sstevel@tonic-gate 	char	**hn, **sn;
21650Sstevel@tonic-gate 
2166132Srobinson 	if ((result = malloc(sizeof (struct nd_hostservlist))) == 0)
21670Sstevel@tonic-gate 		return (ND_NOMEM);
21680Sstevel@tonic-gate 
21690Sstevel@tonic-gate 	/*
21700Sstevel@tonic-gate 	 * We initialize the counters to 1 rather than zero because
21710Sstevel@tonic-gate 	 * we have to count the "official" name as well as the aliases.
21720Sstevel@tonic-gate 	 */
2173*7752SMichen.Chang@Sun.COM 	for (hn = he->h_aliases, hosts = 1; hn && *hn; hn++, hosts++) {};
2174*7752SMichen.Chang@Sun.COM 	if (se) {
2175*7752SMichen.Chang@Sun.COM 		for (sn = se->s_aliases, servs = 1; sn && *sn; sn++, servs++) {
2176*7752SMichen.Chang@Sun.COM 		};
2177*7752SMichen.Chang@Sun.COM 	} else
21780Sstevel@tonic-gate 		servs = 1;
21790Sstevel@tonic-gate 
2180132Srobinson 	if ((hs = calloc(hosts * servs, sizeof (struct nd_hostserv))) == 0) {
2181132Srobinson 		free(result);
21820Sstevel@tonic-gate 		return (ND_NOMEM);
21830Sstevel@tonic-gate 	}
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 	result->h_cnt	= servs * hosts;
21860Sstevel@tonic-gate 	result->h_hostservs = hs;
21870Sstevel@tonic-gate 
21880Sstevel@tonic-gate 	for (i = 0, hn = he->h_aliases; i < hosts; i++) {
21890Sstevel@tonic-gate 		sn = se ? se->s_aliases : NULL;
21900Sstevel@tonic-gate 
21910Sstevel@tonic-gate 		for (j = 0; j < servs; j++) {
21920Sstevel@tonic-gate 			if (i == 0)
21930Sstevel@tonic-gate 				hs->h_host = strdup(he->h_name);
21940Sstevel@tonic-gate 			else
21950Sstevel@tonic-gate 				hs->h_host = strdup(*hn);
21960Sstevel@tonic-gate 			if (j == 0) {
21970Sstevel@tonic-gate 				if (se)
21980Sstevel@tonic-gate 					hs->h_serv = strdup(se->s_name);
21990Sstevel@tonic-gate 				else {
22000Sstevel@tonic-gate 					/* Convert to a number string */
22010Sstevel@tonic-gate 					char stmp[16];
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate 					(void) sprintf(stmp, "%d", port);
22040Sstevel@tonic-gate 					hs->h_serv = strdup(stmp);
22050Sstevel@tonic-gate 				}
22060Sstevel@tonic-gate 			} else
22070Sstevel@tonic-gate 				hs->h_serv = strdup(*sn++);
22080Sstevel@tonic-gate 
22090Sstevel@tonic-gate 			if ((hs->h_host == 0) || (hs->h_serv == 0)) {
2210132Srobinson 				free(result->h_hostservs);
2211132Srobinson 				free(result);
22120Sstevel@tonic-gate 				return (ND_NOMEM);
22130Sstevel@tonic-gate 			}
22140Sstevel@tonic-gate 			hs++;
22150Sstevel@tonic-gate 		}
22160Sstevel@tonic-gate 		if (i)
22170Sstevel@tonic-gate 			hn++;
22180Sstevel@tonic-gate 	}
22190Sstevel@tonic-gate 	*(hslist) = result;
22200Sstevel@tonic-gate 	return (ND_OK);
22210Sstevel@tonic-gate }
22220Sstevel@tonic-gate 
22230Sstevel@tonic-gate /*
22240Sstevel@tonic-gate  * Process results from nd_addrlist ( returned by netdir_getbyname)
22250Sstevel@tonic-gate  * into a hostent using buf.
22260Sstevel@tonic-gate  * *** ASSUMES that nd_addrlist->n_addrs->buf contains IP addresses in
22270Sstevel@tonic-gate  * sockaddr_in's ***
22280Sstevel@tonic-gate  */
22290Sstevel@tonic-gate int
ndaddr2hent(int af,const char * nam,struct nd_addrlist * addrs,struct hostent * result,char * buffer,int buflen)22300Sstevel@tonic-gate ndaddr2hent(int af, const char *nam, struct nd_addrlist *addrs,
22310Sstevel@tonic-gate     struct hostent *result, char *buffer, int buflen)
22320Sstevel@tonic-gate {
22330Sstevel@tonic-gate 	int	i, count;
22340Sstevel@tonic-gate 	struct	in_addr *addrp;
22350Sstevel@tonic-gate 	struct	in6_addr *addr6p;
22360Sstevel@tonic-gate 	char	**addrvec;
22370Sstevel@tonic-gate 	struct	netbuf *na;
22380Sstevel@tonic-gate 	size_t	len;
22390Sstevel@tonic-gate 
22400Sstevel@tonic-gate 	result->h_name		= buffer;
22410Sstevel@tonic-gate 	result->h_addrtype	= af;
22420Sstevel@tonic-gate 	result->h_length	= (af == AF_INET) ? sizeof (*addrp):
2243*7752SMichen.Chang@Sun.COM 	    sizeof (*addr6p);
22440Sstevel@tonic-gate 
22450Sstevel@tonic-gate 	/*
22460Sstevel@tonic-gate 	 * Build addrlist at start of buffer (after name);  store the
22470Sstevel@tonic-gate 	 * addresses themselves at the end of the buffer.
22480Sstevel@tonic-gate 	 */
22490Sstevel@tonic-gate 	len = strlen(nam) + 1;
22500Sstevel@tonic-gate 	addrvec = (char **)ROUND_UP(buffer + len, sizeof (*addrvec));
22510Sstevel@tonic-gate 	result->h_addr_list 	= addrvec;
22520Sstevel@tonic-gate 
22530Sstevel@tonic-gate 	if (af == AF_INET) {
22540Sstevel@tonic-gate 		addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen,
22550Sstevel@tonic-gate 		    sizeof (*addrp));
22560Sstevel@tonic-gate 
22570Sstevel@tonic-gate 		count = addrs->n_cnt;
22580Sstevel@tonic-gate 		if ((char *)(&addrvec[count + 1]) > (char *)(&addrp[-count]))
22590Sstevel@tonic-gate 			return (ND_NOMEM);
22600Sstevel@tonic-gate 
22610Sstevel@tonic-gate 		(void) memcpy(buffer, nam, len);
22620Sstevel@tonic-gate 
22630Sstevel@tonic-gate 		for (na = addrs->n_addrs, i = 0;  i < count;  na++, i++) {
22640Sstevel@tonic-gate 			--addrp;
22650Sstevel@tonic-gate 			(void) memcpy(addrp,
2266132Srobinson 			    /* LINTED pointer cast */
22670Sstevel@tonic-gate 			    &((struct sockaddr_in *)na->buf)->sin_addr,
22680Sstevel@tonic-gate 			    sizeof (*addrp));
22690Sstevel@tonic-gate 			*addrvec++ = (char *)addrp;
22700Sstevel@tonic-gate 		}
22710Sstevel@tonic-gate 	} else {
22720Sstevel@tonic-gate 		addr6p = (struct in6_addr *)ROUND_DOWN(buffer + buflen,
2273*7752SMichen.Chang@Sun.COM 		    sizeof (*addr6p));
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate 		count = addrs->n_cnt;
22760Sstevel@tonic-gate 		if ((char *)(&addrvec[count + 1]) > (char *)(&addr6p[-count]))
22770Sstevel@tonic-gate 			return (ND_NOMEM);
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 		(void) memcpy(buffer, nam, len);
22800Sstevel@tonic-gate 
22810Sstevel@tonic-gate 		for (na = addrs->n_addrs, i = 0;  i < count;  na++, i++) {
22820Sstevel@tonic-gate 			--addr6p;
22830Sstevel@tonic-gate 			(void) memcpy(addr6p,
2284132Srobinson 			    /* LINTED pointer cast */
22850Sstevel@tonic-gate 			    &((struct sockaddr_in6 *)na->buf)->sin6_addr,
22860Sstevel@tonic-gate 			    sizeof (*addr6p));
22870Sstevel@tonic-gate 			*addrvec++ = (char *)addr6p;
22880Sstevel@tonic-gate 		}
22890Sstevel@tonic-gate 	}
22900Sstevel@tonic-gate 	*addrvec = 0;
22910Sstevel@tonic-gate 	result->h_aliases = addrvec;
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate 	return (ND_OK);
22940Sstevel@tonic-gate }
22950Sstevel@tonic-gate 
22960Sstevel@tonic-gate /*
22970Sstevel@tonic-gate  * Process results from nd_addrlist ( returned by netdir_getbyname)
22980Sstevel@tonic-gate  * into a servent using buf.
22990Sstevel@tonic-gate  */
23000Sstevel@tonic-gate int
ndaddr2srent(const char * name,const char * proto,ushort_t port,struct servent * result,char * buffer,int buflen)23010Sstevel@tonic-gate ndaddr2srent(const char *name, const char *proto, ushort_t port,
23020Sstevel@tonic-gate     struct servent *result, char *buffer, int buflen)
23030Sstevel@tonic-gate {
23040Sstevel@tonic-gate 	size_t	i;
23050Sstevel@tonic-gate 	char	*bufend = (buffer + buflen);
23060Sstevel@tonic-gate 
23070Sstevel@tonic-gate 	result->s_port = (int)port;
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate 	result->s_aliases =
23100Sstevel@tonic-gate 	    (char **)ROUND_UP(buffer, sizeof (char *));
23110Sstevel@tonic-gate 	result->s_aliases[0] = NULL;
23120Sstevel@tonic-gate 	buffer = (char *)&result->s_aliases[1];
23130Sstevel@tonic-gate 	result->s_name = buffer;
23140Sstevel@tonic-gate 	i = strlen(name) + 1;
23150Sstevel@tonic-gate 	if ((buffer + i) > bufend)
23160Sstevel@tonic-gate 		return (ND_NOMEM);
23170Sstevel@tonic-gate 	(void) memcpy(buffer, name, i);
23180Sstevel@tonic-gate 	buffer += i;
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 	result->s_proto	= buffer;
23210Sstevel@tonic-gate 	i = strlen(proto) + 1;
23220Sstevel@tonic-gate 	if ((buffer + i) > bufend)
23230Sstevel@tonic-gate 		return (ND_NOMEM);
23240Sstevel@tonic-gate 	(void) memcpy(buffer, proto, i);
23250Sstevel@tonic-gate 	buffer += i;
23260Sstevel@tonic-gate 
23270Sstevel@tonic-gate 	return (ND_OK);
23280Sstevel@tonic-gate }
23290Sstevel@tonic-gate 
23300Sstevel@tonic-gate /*
23310Sstevel@tonic-gate  * Process results from nd_hostservlist ( returned by netdir_getbyaddr)
23320Sstevel@tonic-gate  * into a hostent using buf.
23330Sstevel@tonic-gate  * *** ASSUMES that nd_buf->buf is a sockaddr_in ***
23340Sstevel@tonic-gate  */
23350Sstevel@tonic-gate int
ndhostserv2hent(struct netbuf * nbuf,struct nd_hostservlist * addrs,struct hostent * result,char * buffer,int buflen)23360Sstevel@tonic-gate ndhostserv2hent(struct netbuf *nbuf, struct nd_hostservlist *addrs,
23370Sstevel@tonic-gate     struct hostent *result, char *buffer, int buflen)
23380Sstevel@tonic-gate {
23390Sstevel@tonic-gate 	int	i, count;
23400Sstevel@tonic-gate 	char	*aliasp;
23410Sstevel@tonic-gate 	char	**aliasvec;
23420Sstevel@tonic-gate 	struct	sockaddr_in *sa;
23430Sstevel@tonic-gate 	struct	nd_hostserv *hs;
23440Sstevel@tonic-gate 	const	char *la;
23450Sstevel@tonic-gate 	size_t	length;
23460Sstevel@tonic-gate 
23470Sstevel@tonic-gate 	/* First, give the lonely address a specious home in h_addr_list. */
23480Sstevel@tonic-gate 	aliasp   = (char  *)ROUND_UP(buffer, sizeof (sa->sin_addr));
2349132Srobinson 	/* LINTED pointer cast */
23500Sstevel@tonic-gate 	sa = (struct sockaddr_in *)nbuf->buf;
2351132Srobinson 	(void) memcpy(aliasp, &(sa->sin_addr), sizeof (sa->sin_addr));
23520Sstevel@tonic-gate 	aliasvec = (char **)ROUND_UP(aliasp + sizeof (sa->sin_addr),
2353*7752SMichen.Chang@Sun.COM 	    sizeof (*aliasvec));
23540Sstevel@tonic-gate 	result->h_addr_list = aliasvec;
23550Sstevel@tonic-gate 	*aliasvec++ = aliasp;
23560Sstevel@tonic-gate 	*aliasvec++ = 0;
23570Sstevel@tonic-gate 
23580Sstevel@tonic-gate 	/*
23590Sstevel@tonic-gate 	 * Build h_aliases at start of buffer (after addr and h_addr_list);
23600Sstevel@tonic-gate 	 * store the alias strings at the end of the buffer (before h_name).
23610Sstevel@tonic-gate 	 */
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate 	aliasp = buffer + buflen;
23640Sstevel@tonic-gate 
23650Sstevel@tonic-gate 	result->h_aliases	= aliasvec;
23660Sstevel@tonic-gate 
23670Sstevel@tonic-gate 	hs = addrs->h_hostservs;
2368132Srobinson 	if (!hs)
23690Sstevel@tonic-gate 		return (ND_NOHOST);
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 	length = strlen(hs->h_host) + 1;
23720Sstevel@tonic-gate 	aliasp -= length;
23730Sstevel@tonic-gate 	if ((char *)(&aliasvec[1]) > aliasp)
23740Sstevel@tonic-gate 		return (ND_NOMEM);
23750Sstevel@tonic-gate 	(void) memcpy(aliasp, hs->h_host, length);
23760Sstevel@tonic-gate 
23770Sstevel@tonic-gate 	result->h_name		= aliasp;
23780Sstevel@tonic-gate 	result->h_addrtype	= AF_INET;
23790Sstevel@tonic-gate 	result->h_length	= sizeof (sa->sin_addr);
23800Sstevel@tonic-gate 
23810Sstevel@tonic-gate 	/*
23820Sstevel@tonic-gate 	 * Assumption: the netdir nametoaddr_libs
23830Sstevel@tonic-gate 	 * sort the vector of (host, serv) pairs in such a way that
23840Sstevel@tonic-gate 	 * all pairs with the same host name are contiguous.
23850Sstevel@tonic-gate 	 */
23860Sstevel@tonic-gate 	la = hs->h_host;
23870Sstevel@tonic-gate 	count = addrs->h_cnt;
23880Sstevel@tonic-gate 	for (i = 0;  i < count;  i++, hs++)
23890Sstevel@tonic-gate 		if (strcmp(la, hs->h_host) != 0) {
23900Sstevel@tonic-gate 			size_t len = strlen(hs->h_host) + 1;
23910Sstevel@tonic-gate 
23920Sstevel@tonic-gate 			aliasp -= len;
23930Sstevel@tonic-gate 			if ((char *)(&aliasvec[2]) > aliasp)
23940Sstevel@tonic-gate 				return (ND_NOMEM);
23950Sstevel@tonic-gate 			(void) memcpy(aliasp, hs->h_host, len);
23960Sstevel@tonic-gate 			*aliasvec++ = aliasp;
23970Sstevel@tonic-gate 			la = hs->h_host;
23980Sstevel@tonic-gate 		}
23990Sstevel@tonic-gate 	*aliasvec = 0;
24000Sstevel@tonic-gate 
24010Sstevel@tonic-gate 	return (ND_OK);
24020Sstevel@tonic-gate }
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate /*
24050Sstevel@tonic-gate  * Process results from nd_hostservlist ( returned by netdir_getbyaddr)
24060Sstevel@tonic-gate  * into a servent using buf.
24070Sstevel@tonic-gate  */
24080Sstevel@tonic-gate int
ndhostserv2srent(int port,const char * proto,struct nd_hostservlist * addrs,struct servent * result,char * buffer,int buflen)24090Sstevel@tonic-gate ndhostserv2srent(int port, const char *proto, struct nd_hostservlist *addrs,
24100Sstevel@tonic-gate     struct servent *result, char *buffer, int buflen)
24110Sstevel@tonic-gate {
24120Sstevel@tonic-gate 	int	i, count;
24130Sstevel@tonic-gate 	char	*aliasp;
24140Sstevel@tonic-gate 	char	**aliasvec;
24150Sstevel@tonic-gate 	struct	nd_hostserv *hs;
24160Sstevel@tonic-gate 	const	char *host_cname;
24170Sstevel@tonic-gate 	size_t	leni, lenj;
24180Sstevel@tonic-gate 
24190Sstevel@tonic-gate 	result->s_port = port;
24200Sstevel@tonic-gate 	/*
24210Sstevel@tonic-gate 	 * Build s_aliases at start of buffer;
24220Sstevel@tonic-gate 	 * store proto and aliases at the end of the buffer (before h_name).
24230Sstevel@tonic-gate 	 */
24240Sstevel@tonic-gate 
24250Sstevel@tonic-gate 	aliasp = buffer + buflen;
24260Sstevel@tonic-gate 	aliasvec = (char **)ROUND_UP(buffer, sizeof (char *));
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 	result->s_aliases	= aliasvec;
24290Sstevel@tonic-gate 
24300Sstevel@tonic-gate 	hs = addrs->h_hostservs;
2431132Srobinson 	if (!hs)
24320Sstevel@tonic-gate 		return (ND_NOHOST);
24330Sstevel@tonic-gate 	host_cname = hs->h_host;
24340Sstevel@tonic-gate 
24350Sstevel@tonic-gate 	leni = strlen(proto) + 1;
24360Sstevel@tonic-gate 	lenj = strlen(hs->h_serv) + 1;
24370Sstevel@tonic-gate 	if ((char *)(&aliasvec[2]) > (aliasp - leni - lenj))
24380Sstevel@tonic-gate 		return (ND_NOMEM);
24390Sstevel@tonic-gate 
24400Sstevel@tonic-gate 	aliasp -= leni;
24410Sstevel@tonic-gate 	(void) memcpy(aliasp, proto, leni);
24420Sstevel@tonic-gate 	result->s_proto = aliasp;
24430Sstevel@tonic-gate 
24440Sstevel@tonic-gate 	aliasp -= lenj;
24450Sstevel@tonic-gate 	(void) memcpy(aliasp, hs->h_serv, lenj);
24460Sstevel@tonic-gate 	result->s_name = aliasp;
24470Sstevel@tonic-gate 
24480Sstevel@tonic-gate 	/*
24490Sstevel@tonic-gate 	 * Assumption: the netdir nametoaddr_libs
24500Sstevel@tonic-gate 	 * do a host aliases first and serv aliases next
24510Sstevel@tonic-gate 	 * enumeration for creating the list of hostserv
24520Sstevel@tonic-gate 	 * structures.
24530Sstevel@tonic-gate 	 */
24540Sstevel@tonic-gate 	count = addrs->h_cnt;
24550Sstevel@tonic-gate 	for (i = 0;
24560Sstevel@tonic-gate 	    i < count && hs->h_serv && strcmp(hs->h_host, host_cname) == 0;
24570Sstevel@tonic-gate 	    i++, hs++) {
24580Sstevel@tonic-gate 		size_t len = strlen(hs->h_serv) + 1;
24590Sstevel@tonic-gate 
24600Sstevel@tonic-gate 		aliasp -= len;
24610Sstevel@tonic-gate 		if ((char *)(&aliasvec[2]) > aliasp)
24620Sstevel@tonic-gate 			return (ND_NOMEM);
24630Sstevel@tonic-gate 		(void) memcpy(aliasp, hs->h_serv, len);
24640Sstevel@tonic-gate 		*aliasvec++ = aliasp;
24650Sstevel@tonic-gate 	}
24660Sstevel@tonic-gate 	*aliasvec = NULL;
24670Sstevel@tonic-gate 
24680Sstevel@tonic-gate 	return (ND_OK);
24690Sstevel@tonic-gate }
24700Sstevel@tonic-gate 
24710Sstevel@tonic-gate 
24720Sstevel@tonic-gate static int
nd2herrno(int nerr)24730Sstevel@tonic-gate nd2herrno(int nerr)
24740Sstevel@tonic-gate {
24750Sstevel@tonic-gate 	switch (nerr) {
24760Sstevel@tonic-gate 	case ND_OK:
24770Sstevel@tonic-gate 		return (0);
24780Sstevel@tonic-gate 	case ND_TRY_AGAIN:
24790Sstevel@tonic-gate 		return (TRY_AGAIN);
24800Sstevel@tonic-gate 	case ND_NO_RECOVERY:
24810Sstevel@tonic-gate 	case ND_BADARG:
24820Sstevel@tonic-gate 	case ND_NOMEM:
24830Sstevel@tonic-gate 		return (NO_RECOVERY);
24840Sstevel@tonic-gate 	case ND_NO_DATA:
24850Sstevel@tonic-gate 		return (NO_DATA);
24860Sstevel@tonic-gate 	case ND_NOHOST:
24870Sstevel@tonic-gate 	case ND_NOSERV:
24880Sstevel@tonic-gate 		return (HOST_NOT_FOUND);
24890Sstevel@tonic-gate 	default:
24900Sstevel@tonic-gate 		return (NO_RECOVERY);
24910Sstevel@tonic-gate 	}
24920Sstevel@tonic-gate }
24930Sstevel@tonic-gate 
24940Sstevel@tonic-gate /*
24950Sstevel@tonic-gate  * This is a utility function so that various parts of libnsl can
24960Sstevel@tonic-gate  * easily send ioctls down to ip.
24970Sstevel@tonic-gate  *
24980Sstevel@tonic-gate  */
24990Sstevel@tonic-gate int
nss_ioctl(int af,int cmd,void * arg)25000Sstevel@tonic-gate nss_ioctl(int af, int cmd, void *arg)
25010Sstevel@tonic-gate {
25020Sstevel@tonic-gate 	int	fd;
25030Sstevel@tonic-gate 	char	*devpath;
25040Sstevel@tonic-gate 	int	retv;
25050Sstevel@tonic-gate 
25060Sstevel@tonic-gate 	switch (af) {
25070Sstevel@tonic-gate 	case AF_INET6:
25080Sstevel@tonic-gate 		devpath = UDP6DEV;
25090Sstevel@tonic-gate 		break;
25100Sstevel@tonic-gate 	case AF_INET:
25110Sstevel@tonic-gate 	case AF_UNSPEC:
25120Sstevel@tonic-gate 	default:
25130Sstevel@tonic-gate 		devpath = UDPDEV;
25140Sstevel@tonic-gate 	}
25150Sstevel@tonic-gate 	if ((fd = open(devpath, O_RDONLY)) < 0) {
25160Sstevel@tonic-gate 		return (-1);
25170Sstevel@tonic-gate 	}
25180Sstevel@tonic-gate 	while ((retv = ioctl(fd, cmd, arg)) == -1) {
25190Sstevel@tonic-gate 		if (errno != EINTR)
25200Sstevel@tonic-gate 	break;
25210Sstevel@tonic-gate 	}
2522132Srobinson 	(void) close(fd);
25230Sstevel@tonic-gate 	return (retv);
25240Sstevel@tonic-gate }
25250Sstevel@tonic-gate 
25260Sstevel@tonic-gate static int
nss_strioctl(int af,int cmd,void * ptr,int ilen)25270Sstevel@tonic-gate nss_strioctl(int af, int cmd, void *ptr, int ilen)
25280Sstevel@tonic-gate {
25290Sstevel@tonic-gate 	struct strioctl str;
25300Sstevel@tonic-gate 
25310Sstevel@tonic-gate 	str.ic_cmd = cmd;
25320Sstevel@tonic-gate 	str.ic_timout = 0;
25330Sstevel@tonic-gate 	str.ic_len = ilen;
25340Sstevel@tonic-gate 	str.ic_dp = ptr;
25350Sstevel@tonic-gate 
25360Sstevel@tonic-gate 	return (nss_ioctl(af, I_STR, &str));
25370Sstevel@tonic-gate }
25380Sstevel@tonic-gate 
25390Sstevel@tonic-gate static struct ifinfo *
get_local_info(void)25400Sstevel@tonic-gate get_local_info(void)
25410Sstevel@tonic-gate {
25420Sstevel@tonic-gate 	int	numifs;
25430Sstevel@tonic-gate 	int	n;
25440Sstevel@tonic-gate 	char	*buf = NULL;
25450Sstevel@tonic-gate 	size_t	needed;
25460Sstevel@tonic-gate 	struct lifconf	lifc;
25470Sstevel@tonic-gate 	struct lifreq	lifreq, *lifr;
25480Sstevel@tonic-gate 	struct lifnum	lifn;
25490Sstevel@tonic-gate 	struct ifinfo	*localinfo;
25500Sstevel@tonic-gate 
25510Sstevel@tonic-gate 	lifn.lifn_family = AF_UNSPEC;
25520Sstevel@tonic-gate 	lifn.lifn_flags = 0;
25530Sstevel@tonic-gate 
25540Sstevel@tonic-gate getifnum:
25550Sstevel@tonic-gate 	if (nss_ioctl(AF_UNSPEC, SIOCGLIFNUM, &lifn) == -1) {
25560Sstevel@tonic-gate 		numifs = MAXIFS;
25570Sstevel@tonic-gate 	} else {
25580Sstevel@tonic-gate 		numifs = lifn.lifn_count;
25590Sstevel@tonic-gate 	}
25600Sstevel@tonic-gate 
25610Sstevel@tonic-gate 	/*
25620Sstevel@tonic-gate 	 * Add a small fudge factor in case interfaces get plumbed between
25630Sstevel@tonic-gate 	 * the call to SIOCGLIFNUM and SIOCGLIFCONF.
25640Sstevel@tonic-gate 	 */
25650Sstevel@tonic-gate 	needed = (numifs + 4) * sizeof (lifreq);
25660Sstevel@tonic-gate 	if (buf == NULL)
25670Sstevel@tonic-gate 		buf = malloc(needed);
25680Sstevel@tonic-gate 	else
25690Sstevel@tonic-gate 		buf = realloc(buf, needed);
25700Sstevel@tonic-gate 	if (buf == NULL) {
25710Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m");
25720Sstevel@tonic-gate 		_nderror = ND_NOMEM;
25730Sstevel@tonic-gate 		return (NULL);
25740Sstevel@tonic-gate 	}
25750Sstevel@tonic-gate 	lifc.lifc_family = AF_UNSPEC;
25760Sstevel@tonic-gate 	lifc.lifc_flags = 0;
25770Sstevel@tonic-gate 	lifc.lifc_len = needed;
25780Sstevel@tonic-gate 	lifc.lifc_buf = buf;
25790Sstevel@tonic-gate 	if (nss_ioctl(AF_UNSPEC, SIOCGLIFCONF, &lifc) == -1) {
25800Sstevel@tonic-gate 		/*
25810Sstevel@tonic-gate 		 * IP returns EINVAL if the buffer was too small to fit
25820Sstevel@tonic-gate 		 * all of the entries.  If that's the case, go back and
25830Sstevel@tonic-gate 		 * try again.
25840Sstevel@tonic-gate 		 */
25850Sstevel@tonic-gate 		if (errno == EINVAL)
25860Sstevel@tonic-gate 			goto getifnum;
25870Sstevel@tonic-gate 
25880Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "n2a get_local_info: "
25890Sstevel@tonic-gate 		    "ioctl (get interface configuration): %m");
25900Sstevel@tonic-gate 		free(buf);
25910Sstevel@tonic-gate 		_nderror = ND_SYSTEM;
25920Sstevel@tonic-gate 		return (NULL);
25930Sstevel@tonic-gate 	}
2594132Srobinson 	/* LINTED pointer cast */
25950Sstevel@tonic-gate 	lifr = (struct lifreq *)buf;
25960Sstevel@tonic-gate 	numifs = lifc.lifc_len/sizeof (lifreq);
2597132Srobinson 	localinfo = malloc(ifinfosize(numifs));
25980Sstevel@tonic-gate 	if (localinfo == NULL) {
25990Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m");
26000Sstevel@tonic-gate 		free(buf);
26010Sstevel@tonic-gate 		_nderror = ND_SYSTEM;
26020Sstevel@tonic-gate 		return (NULL);
26030Sstevel@tonic-gate 	}
26040Sstevel@tonic-gate 
2605132Srobinson 	/* LINTED pointer cast */
26060Sstevel@tonic-gate 	localinfo->addresses = (struct __ifaddr *)
26070Sstevel@tonic-gate 	    ((char *)localinfo + sizeof (struct ifinfo));
26080Sstevel@tonic-gate 
26090Sstevel@tonic-gate 	for (localinfo->count = 0, n = numifs; n > 0; n--, lifr++) {
26100Sstevel@tonic-gate 		int af;
26110Sstevel@tonic-gate 
26120Sstevel@tonic-gate 		lifreq = *lifr;
26130Sstevel@tonic-gate 		af = lifreq.lifr_addr.ss_family;
26140Sstevel@tonic-gate 
26150Sstevel@tonic-gate 		/* Squirrel away the address */
26160Sstevel@tonic-gate 		if (ifassign(lifreq, localinfo->count, IF_ADDR) == 0)
26170Sstevel@tonic-gate 			continue;
26180Sstevel@tonic-gate 
26190Sstevel@tonic-gate 		if (nss_ioctl(af, SIOCGLIFFLAGS, &lifreq) < 0) {
26200Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
26210Sstevel@tonic-gate 			    "n2a get_local_info: "
26220Sstevel@tonic-gate 			    "ioctl (get interface flags): %m");
26230Sstevel@tonic-gate 			continue;
26240Sstevel@tonic-gate 		}
26250Sstevel@tonic-gate 		if (!(lifreq.lifr_flags & IFF_UP))
26260Sstevel@tonic-gate 			continue;
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate 		if (nss_ioctl(af, SIOCGLIFNETMASK, &lifreq) < 0) {
26290Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
26300Sstevel@tonic-gate 			    "n2a get_local_info: "
26310Sstevel@tonic-gate 			    "ioctl (get interface netmask): %m");
26320Sstevel@tonic-gate 			continue;
26330Sstevel@tonic-gate 		}
26340Sstevel@tonic-gate 
26350Sstevel@tonic-gate 		if (ifassign(lifreq, localinfo->count, IF_MASK) == 0)
26360Sstevel@tonic-gate 			continue;
26370Sstevel@tonic-gate 
26380Sstevel@tonic-gate 		localinfo->count++;
26390Sstevel@tonic-gate 	}
26400Sstevel@tonic-gate 
26410Sstevel@tonic-gate 	free(buf);
26420Sstevel@tonic-gate 	return (localinfo);
26430Sstevel@tonic-gate }
26440Sstevel@tonic-gate 
26450Sstevel@tonic-gate static int
__inet_ifassign(sa_family_t af,struct __ifaddr * ifa,__ifaddr_type type,void * addr)26460Sstevel@tonic-gate __inet_ifassign(sa_family_t af, struct __ifaddr *ifa, __ifaddr_type type,
26470Sstevel@tonic-gate     void *addr) {
26480Sstevel@tonic-gate 	switch (type) {
26490Sstevel@tonic-gate 	case IF_ADDR:
26500Sstevel@tonic-gate 		ifa->af = af;
26510Sstevel@tonic-gate 		if (af == AF_INET6) {
26520Sstevel@tonic-gate 			ifa->addr.in6 = *(struct in6_addr *)addr;
26530Sstevel@tonic-gate 		} else {
26540Sstevel@tonic-gate 			ifa->addr.in4 = *(struct in_addr *)addr;
26550Sstevel@tonic-gate 		}
26560Sstevel@tonic-gate 		break;
26570Sstevel@tonic-gate 	case IF_MASK:
26580Sstevel@tonic-gate 		if (ifa->af == af) {
26590Sstevel@tonic-gate 			if (af == AF_INET6) {
26600Sstevel@tonic-gate 				ifa->mask.in6 = *(struct in6_addr *)addr;
26610Sstevel@tonic-gate 			} else {
26620Sstevel@tonic-gate 				ifa->mask.in4 = *(struct in_addr *)addr;
26630Sstevel@tonic-gate 			}
26640Sstevel@tonic-gate 		} else {
26650Sstevel@tonic-gate 			return (0);
26660Sstevel@tonic-gate 		}
26670Sstevel@tonic-gate 		break;
26680Sstevel@tonic-gate 	default:
26690Sstevel@tonic-gate 		return (0);
26700Sstevel@tonic-gate 	}
26710Sstevel@tonic-gate 
26720Sstevel@tonic-gate 	return (1);
26730Sstevel@tonic-gate }
26740Sstevel@tonic-gate 
26750Sstevel@tonic-gate /*
26760Sstevel@tonic-gate  *  Some higher-level routines for determining if an address is
26770Sstevel@tonic-gate  *  on a local network.
26780Sstevel@tonic-gate  *
26790Sstevel@tonic-gate  *      __inet_get_local_interfaces() - get an opaque handle with
26800Sstevel@tonic-gate  *          with a list of local interfaces
26810Sstevel@tonic-gate  *      __inet_address_is_local() - return 1 if an address is
26820Sstevel@tonic-gate  *          on a local network; 0 otherwise
26830Sstevel@tonic-gate  *      __inet_free_local_interfaces() - free handle that was
26840Sstevel@tonic-gate  *          returned by __inet_get_local_interfaces()
26850Sstevel@tonic-gate  *
26860Sstevel@tonic-gate  *  A typical calling sequence is:
26870Sstevel@tonic-gate  *
26880Sstevel@tonic-gate  *      p = __inet_get_local_interfaces();
26890Sstevel@tonic-gate  *      if (__inet_address_is_local(p, inaddr)) {
26900Sstevel@tonic-gate  *          ...
26910Sstevel@tonic-gate  *      }
26920Sstevel@tonic-gate  *      __inet_free_local_interfaces(p);
26930Sstevel@tonic-gate  */
26940Sstevel@tonic-gate 
26950Sstevel@tonic-gate /*
26960Sstevel@tonic-gate  *  Return an opaque pointer to a list of configured interfaces.
26970Sstevel@tonic-gate  */
26980Sstevel@tonic-gate void *
__inet_get_local_interfaces(void)26990Sstevel@tonic-gate __inet_get_local_interfaces(void)
27000Sstevel@tonic-gate {
27010Sstevel@tonic-gate 	return (get_local_info());
27020Sstevel@tonic-gate }
27030Sstevel@tonic-gate 
27040Sstevel@tonic-gate /*
27050Sstevel@tonic-gate  *  Free memory allocated by inet_local_interfaces().
27060Sstevel@tonic-gate  */
27070Sstevel@tonic-gate void
__inet_free_local_interfaces(void * p)27080Sstevel@tonic-gate __inet_free_local_interfaces(void *p)
27090Sstevel@tonic-gate {
27100Sstevel@tonic-gate 	free(p);
27110Sstevel@tonic-gate }
27120Sstevel@tonic-gate 
27130Sstevel@tonic-gate /*
27140Sstevel@tonic-gate  *  Determine if an address is on a local network.
27150Sstevel@tonic-gate  *
27160Sstevel@tonic-gate  *  Might have made sense to use SIOCTONLINK, except that it doesn't
27170Sstevel@tonic-gate  *  handle matching on IPv4 network addresses.
27180Sstevel@tonic-gate  */
27190Sstevel@tonic-gate int
__inet_address_is_local_af(void * p,sa_family_t af,void * addr)27200Sstevel@tonic-gate __inet_address_is_local_af(void *p, sa_family_t af, void *addr) {
27210Sstevel@tonic-gate 
27220Sstevel@tonic-gate 	struct ifinfo	*localinfo = (struct ifinfo *)p;
27230Sstevel@tonic-gate 	int		i, a;
27240Sstevel@tonic-gate 	struct in_addr	v4addr;
27250Sstevel@tonic-gate 
27260Sstevel@tonic-gate 	if (localinfo == 0)
27270Sstevel@tonic-gate 		return (0);
27280Sstevel@tonic-gate 
27290Sstevel@tonic-gate 	if (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr)) {
27300Sstevel@tonic-gate 		IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addr, &v4addr);
27310Sstevel@tonic-gate 		af = AF_INET;
27320Sstevel@tonic-gate 		addr = (void *)&v4addr;
27330Sstevel@tonic-gate 	}
27340Sstevel@tonic-gate 
27350Sstevel@tonic-gate 	for (i = 0; i < localinfo->count; i++) {
27360Sstevel@tonic-gate 		if (ifaf(i) == af) {
27370Sstevel@tonic-gate 			if (af == AF_INET6) {
27380Sstevel@tonic-gate 				struct in6_addr *a6 = (struct in6_addr *)addr;
27390Sstevel@tonic-gate 				for (a = 0; a < sizeof (a6->s6_addr); a++) {
27400Sstevel@tonic-gate 					if ((a6->s6_addr[a] &
27410Sstevel@tonic-gate 						ifmask6(i).s6_addr[a]) !=
27420Sstevel@tonic-gate 						(ifaddr6(i).s6_addr[a] &
27430Sstevel@tonic-gate 						ifmask6(i).s6_addr[a]))
27440Sstevel@tonic-gate 						break;
27450Sstevel@tonic-gate 				}
27460Sstevel@tonic-gate 				if (a >= sizeof (a6->s6_addr))
27470Sstevel@tonic-gate 					return (1);
27480Sstevel@tonic-gate 			} else {
27490Sstevel@tonic-gate 				if ((((struct in_addr *)addr)->s_addr &
27500Sstevel@tonic-gate 						ifmask4(i).s_addr) ==
27510Sstevel@tonic-gate 					(ifaddr4(i).s_addr &
27520Sstevel@tonic-gate 						ifmask4(i).s_addr))
27530Sstevel@tonic-gate 					return (1);
27540Sstevel@tonic-gate 			}
27550Sstevel@tonic-gate 		}
27560Sstevel@tonic-gate 	}
27570Sstevel@tonic-gate 
27580Sstevel@tonic-gate 	return (0);
27590Sstevel@tonic-gate }
27600Sstevel@tonic-gate 
27610Sstevel@tonic-gate int
__inet_address_is_local(void * p,struct in_addr addr)27620Sstevel@tonic-gate __inet_address_is_local(void *p, struct in_addr addr)
27630Sstevel@tonic-gate {
27640Sstevel@tonic-gate 	return (__inet_address_is_local_af(p, AF_INET, &addr));
27650Sstevel@tonic-gate }
27660Sstevel@tonic-gate 
27670Sstevel@tonic-gate int
__inet_uaddr_is_local(void * p,struct netconfig * nc,char * uaddr)27680Sstevel@tonic-gate __inet_uaddr_is_local(void *p, struct netconfig *nc, char *uaddr)
27690Sstevel@tonic-gate {
27700Sstevel@tonic-gate 	struct netbuf		*taddr;
27710Sstevel@tonic-gate 	sa_family_t		af;
27720Sstevel@tonic-gate 	int			ret;
27730Sstevel@tonic-gate 
27740Sstevel@tonic-gate 	taddr = uaddr2taddr(nc, uaddr);
27750Sstevel@tonic-gate 	if (taddr == 0)
27760Sstevel@tonic-gate 		return (0);
27770Sstevel@tonic-gate 
2778132Srobinson 	/* LINTED pointer cast */
27790Sstevel@tonic-gate 	af = ((struct sockaddr *)taddr->buf)->sa_family;
27800Sstevel@tonic-gate 
2781*7752SMichen.Chang@Sun.COM 	ret = __inet_address_is_local_af(p, af, (af == AF_INET6) ?
2782*7752SMichen.Chang@Sun.COM 	    /* LINTED pointer cast */
2783*7752SMichen.Chang@Sun.COM 	    (void *)&((struct sockaddr_in6 *)taddr->buf)->sin6_addr :
2784*7752SMichen.Chang@Sun.COM 	    /* LINTED pointer cast */
2785*7752SMichen.Chang@Sun.COM 	    (void *)&((struct sockaddr_in *)taddr->buf)->sin_addr);
27860Sstevel@tonic-gate 
27870Sstevel@tonic-gate 	netdir_free(taddr, ND_ADDR);
27880Sstevel@tonic-gate 	return (ret);
27890Sstevel@tonic-gate }
27900Sstevel@tonic-gate 
27910Sstevel@tonic-gate 
27920Sstevel@tonic-gate int
__inet_address_count(void * p)27930Sstevel@tonic-gate __inet_address_count(void *p)
27940Sstevel@tonic-gate {
27950Sstevel@tonic-gate 	struct ifinfo *lp = (struct ifinfo *)p;
27960Sstevel@tonic-gate 
27970Sstevel@tonic-gate 	if (lp != 0) {
27980Sstevel@tonic-gate 		return (lp->count);
27990Sstevel@tonic-gate 	} else {
28000Sstevel@tonic-gate 		return (0);
28010Sstevel@tonic-gate 	}
28020Sstevel@tonic-gate }
28030Sstevel@tonic-gate 
28040Sstevel@tonic-gate uint32_t
__inet_get_addr(void * p,int n)28050Sstevel@tonic-gate __inet_get_addr(void *p, int n)
28060Sstevel@tonic-gate {
28070Sstevel@tonic-gate 	struct ifinfo *localinfo = (struct ifinfo *)p;
28080Sstevel@tonic-gate 
28090Sstevel@tonic-gate 	if (localinfo == 0 || n >= localinfo->count || ifaf(n) != AF_INET)
28100Sstevel@tonic-gate 		return (0);
28110Sstevel@tonic-gate 
28120Sstevel@tonic-gate 	return (ifaddr4(n).s_addr);
28130Sstevel@tonic-gate }
28140Sstevel@tonic-gate 
28150Sstevel@tonic-gate uint32_t
__inet_get_network(void * p,int n)28160Sstevel@tonic-gate __inet_get_network(void *p, int n)
28170Sstevel@tonic-gate {
28180Sstevel@tonic-gate 	struct ifinfo *localinfo = (struct ifinfo *)p;
28190Sstevel@tonic-gate 
28200Sstevel@tonic-gate 	if (localinfo == 0 || n >= localinfo->count || ifaf(n) != AF_INET)
28210Sstevel@tonic-gate 		return (0);
28220Sstevel@tonic-gate 
28230Sstevel@tonic-gate 	return (ifaddr4(n).s_addr & ifmask4(n).s_addr);
28240Sstevel@tonic-gate }
28250Sstevel@tonic-gate 
28260Sstevel@tonic-gate char *
__inet_get_uaddr(void * p,struct netconfig * nc,int n)28270Sstevel@tonic-gate __inet_get_uaddr(void *p, struct netconfig *nc, int n)
28280Sstevel@tonic-gate {
28290Sstevel@tonic-gate 	struct ifinfo *localinfo = (struct ifinfo *)p;
28300Sstevel@tonic-gate 	char *uaddr;
28310Sstevel@tonic-gate 	struct sockaddr_in sin4;
28320Sstevel@tonic-gate 	struct sockaddr_in6 sin6;
28330Sstevel@tonic-gate 	struct netbuf nb;
28340Sstevel@tonic-gate 
28350Sstevel@tonic-gate 	if (localinfo == 0 || nc == 0 || n >= localinfo->count)
28360Sstevel@tonic-gate 		return (0);
28370Sstevel@tonic-gate 
28380Sstevel@tonic-gate 	if (ifaf(n) == AF_INET6) {
28390Sstevel@tonic-gate 		if (strcmp(NC_INET6, nc->nc_protofmly) != 0)
28400Sstevel@tonic-gate 			return (0);
2841132Srobinson 		(void) memset(&sin6, 0, sizeof (sin6));
28420Sstevel@tonic-gate 		sin6.sin6_family = AF_INET6;
28430Sstevel@tonic-gate 		sin6.sin6_addr = ifaddr6(n);
28440Sstevel@tonic-gate 		nb.buf = (char *)&sin6;
28450Sstevel@tonic-gate 		nb.len = sizeof (sin6);
28460Sstevel@tonic-gate 	} else {
28470Sstevel@tonic-gate 		if (strcmp(NC_INET, nc->nc_protofmly) != 0)
28480Sstevel@tonic-gate 			return (0);
2849132Srobinson 		(void) memset(&sin4, 0, sizeof (sin4));
28500Sstevel@tonic-gate 		sin4.sin_family = AF_INET;
28510Sstevel@tonic-gate 		sin4.sin_addr = ifaddr4(n);
28520Sstevel@tonic-gate 		nb.buf = (char *)&sin4;
28530Sstevel@tonic-gate 		nb.len = sizeof (sin4);
28540Sstevel@tonic-gate 	}
28550Sstevel@tonic-gate 
28560Sstevel@tonic-gate 	nb.maxlen = nb.len;
28570Sstevel@tonic-gate 
28580Sstevel@tonic-gate 	uaddr = taddr2uaddr(nc, &nb);
28590Sstevel@tonic-gate 	return (uaddr);
28600Sstevel@tonic-gate }
28610Sstevel@tonic-gate 
28620Sstevel@tonic-gate char *
__inet_get_networka(void * p,int n)28630Sstevel@tonic-gate __inet_get_networka(void *p, int n)
28640Sstevel@tonic-gate {
28650Sstevel@tonic-gate 	struct ifinfo	*localinfo = (struct ifinfo *)p;
28660Sstevel@tonic-gate 
28670Sstevel@tonic-gate 	if (localinfo == 0 || n >= localinfo->count)
28680Sstevel@tonic-gate 		return (0);
28690Sstevel@tonic-gate 
28700Sstevel@tonic-gate 	if (ifaf(n) == AF_INET6) {
28710Sstevel@tonic-gate 		char		buf[INET6_ADDRSTRLEN];
28720Sstevel@tonic-gate 		struct in6_addr	in6;
28730Sstevel@tonic-gate 		int		i;
28740Sstevel@tonic-gate 
28750Sstevel@tonic-gate 		for (i = 0; i < sizeof (in6.s6_addr); i++) {
28760Sstevel@tonic-gate 			in6.s6_addr[i] = ifaddr6(n).s6_addr[i] &
2877*7752SMichen.Chang@Sun.COM 			    ifmask6(n).s6_addr[i];
28780Sstevel@tonic-gate 		}
28790Sstevel@tonic-gate 		return (strdup(inet_ntop(AF_INET6, &in6, buf, sizeof (buf))));
28800Sstevel@tonic-gate 	} else {
28810Sstevel@tonic-gate 		struct in_addr	in4;
28820Sstevel@tonic-gate 
28830Sstevel@tonic-gate 		in4.s_addr = ifaddr4(n).s_addr & ifmask4(n).s_addr;
28840Sstevel@tonic-gate 		return (strdup(inet_ntoa(in4)));
28850Sstevel@tonic-gate 	}
28860Sstevel@tonic-gate }
28870Sstevel@tonic-gate 
28880Sstevel@tonic-gate static int
in_list(struct in_addr * addrs,int n,struct in_addr a)28890Sstevel@tonic-gate in_list(struct in_addr *addrs, int n, struct in_addr a)
28900Sstevel@tonic-gate {
28910Sstevel@tonic-gate 	int i;
28920Sstevel@tonic-gate 
28930Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
28940Sstevel@tonic-gate 		if (addrs[i].s_addr == a.s_addr)
28950Sstevel@tonic-gate 			return (1);
28960Sstevel@tonic-gate 	}
28970Sstevel@tonic-gate 	return (0);
28980Sstevel@tonic-gate }
28990Sstevel@tonic-gate 
29000Sstevel@tonic-gate static int
getbroadcastnets(struct netconfig * tp,struct in_addr ** addrs)29010Sstevel@tonic-gate getbroadcastnets(struct netconfig *tp, struct in_addr **addrs)
29020Sstevel@tonic-gate {
29030Sstevel@tonic-gate 	struct ifconf ifc;
29040Sstevel@tonic-gate 	struct ifreq ifreq, *ifr;
29050Sstevel@tonic-gate 	struct sockaddr_in *sin;
29060Sstevel@tonic-gate 	struct in_addr a;
29070Sstevel@tonic-gate 	int fd;
29080Sstevel@tonic-gate 	int n, i, numifs;
29090Sstevel@tonic-gate 	char *buf;
29100Sstevel@tonic-gate 	int	use_loopback = 0;
29110Sstevel@tonic-gate 
29120Sstevel@tonic-gate 	_nderror = ND_SYSTEM;
29130Sstevel@tonic-gate 	fd = open(tp->nc_device, O_RDONLY);
29140Sstevel@tonic-gate 	if (fd < 0) {
29150Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
29160Sstevel@tonic-gate 	    "broadcast: open to get interface configuration: %m");
29170Sstevel@tonic-gate 		return (0);
29180Sstevel@tonic-gate 	}
29190Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0)
29200Sstevel@tonic-gate 		numifs = MAXIFS;
2921132Srobinson 	buf = malloc(numifs * sizeof (struct ifreq));
29220Sstevel@tonic-gate 	if (buf == NULL) {
29230Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "broadcast: malloc failed: %m");
29240Sstevel@tonic-gate 		(void) close(fd);
29250Sstevel@tonic-gate 		return (0);
29260Sstevel@tonic-gate 	}
2927132Srobinson 	*addrs = malloc(numifs * sizeof (struct in_addr));
29280Sstevel@tonic-gate 	if (*addrs == NULL) {
29290Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "broadcast: malloc failed: %m");
29300Sstevel@tonic-gate 		free(buf);
29310Sstevel@tonic-gate 		(void) close(fd);
29320Sstevel@tonic-gate 		return (0);
29330Sstevel@tonic-gate 	}
29340Sstevel@tonic-gate 	ifc.ifc_len = numifs * (int)sizeof (struct ifreq);
29350Sstevel@tonic-gate 	ifc.ifc_buf = buf;
29360Sstevel@tonic-gate 	/*
29370Sstevel@tonic-gate 	 * Ideally, this ioctl should also tell me, how many bytes were
29380Sstevel@tonic-gate 	 * finally allocated, but it doesnt.
29390Sstevel@tonic-gate 	 */
29400Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) {
29410Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
29420Sstevel@tonic-gate 	    "broadcast: ioctl (get interface configuration): %m");
29430Sstevel@tonic-gate 		free(buf);
29440Sstevel@tonic-gate 		free(*addrs);
29450Sstevel@tonic-gate 		(void) close(fd);
29460Sstevel@tonic-gate 		return (0);
29470Sstevel@tonic-gate 	}
29480Sstevel@tonic-gate 
29490Sstevel@tonic-gate retry:
2950132Srobinson 	/* LINTED pointer cast */
29510Sstevel@tonic-gate 	ifr = (struct ifreq *)buf;
29520Sstevel@tonic-gate 	for (i = 0, n = ifc.ifc_len / (int)sizeof (struct ifreq);
2953*7752SMichen.Chang@Sun.COM 	    n > 0; n--, ifr++) {
29540Sstevel@tonic-gate 		ifreq = *ifr;
29550Sstevel@tonic-gate 		if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
2956*7752SMichen.Chang@Sun.COM 			(void) syslog(LOG_ERR, "broadcast: "
2957*7752SMichen.Chang@Sun.COM 			    "ioctl (get interface flags): %m");
29580Sstevel@tonic-gate 			continue;
29590Sstevel@tonic-gate 		}
29600Sstevel@tonic-gate 		if (!(ifreq.ifr_flags & IFF_UP) ||
29610Sstevel@tonic-gate 		    (ifr->ifr_addr.sa_family != AF_INET))
29620Sstevel@tonic-gate 			continue;
29630Sstevel@tonic-gate 		if (ifreq.ifr_flags & IFF_BROADCAST) {
2964132Srobinson 			/* LINTED pointer cast */
29650Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&ifr->ifr_addr;
29660Sstevel@tonic-gate 			if (ioctl(fd, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
29670Sstevel@tonic-gate 				/* May not work with other implementation */
29680Sstevel@tonic-gate 				a = _inet_makeaddr(
29690Sstevel@tonic-gate 				    inet_netof(sin->sin_addr),
29700Sstevel@tonic-gate 				    INADDR_ANY);
29710Sstevel@tonic-gate 				if (!in_list(*addrs, i, a))
29720Sstevel@tonic-gate 					(*addrs)[i++] = a;
29730Sstevel@tonic-gate 			} else {
2974132Srobinson 				/* LINTED pointer cast */
29750Sstevel@tonic-gate 				a = ((struct sockaddr_in *)
29760Sstevel@tonic-gate 				    &ifreq.ifr_addr)->sin_addr;
29770Sstevel@tonic-gate 				if (!in_list(*addrs, i, a))
29780Sstevel@tonic-gate 					(*addrs)[i++] = a;
29790Sstevel@tonic-gate 			}
29800Sstevel@tonic-gate 			continue;
29810Sstevel@tonic-gate 		}
29820Sstevel@tonic-gate 		if (use_loopback && (ifreq.ifr_flags & IFF_LOOPBACK)) {
2983132Srobinson 			/* LINTED pointer cast */
29840Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&ifr->ifr_addr;
29850Sstevel@tonic-gate 			a = sin->sin_addr;
29860Sstevel@tonic-gate 			if (!in_list(*addrs, i, a))
29870Sstevel@tonic-gate 				(*addrs)[i++] = a;
29880Sstevel@tonic-gate 			continue;
29890Sstevel@tonic-gate 		}
29900Sstevel@tonic-gate 		if (ifreq.ifr_flags & IFF_POINTOPOINT) {
29910Sstevel@tonic-gate 			if (ioctl(fd, SIOCGIFDSTADDR, (char *)&ifreq) < 0)
29920Sstevel@tonic-gate 				continue;
2993132Srobinson 			/* LINTED pointer cast */
29940Sstevel@tonic-gate 			a = ((struct sockaddr_in *)
29950Sstevel@tonic-gate 			    &ifreq.ifr_addr)->sin_addr;
29960Sstevel@tonic-gate 			if (!in_list(*addrs, i, a))
29970Sstevel@tonic-gate 				(*addrs)[i++] = a;
29980Sstevel@tonic-gate 			continue;
29990Sstevel@tonic-gate 		}
30000Sstevel@tonic-gate 	}
30010Sstevel@tonic-gate 	if (i == 0 && !use_loopback) {
30020Sstevel@tonic-gate 		use_loopback = 1;
30030Sstevel@tonic-gate 		goto retry;
30040Sstevel@tonic-gate 	}
30050Sstevel@tonic-gate 	free(buf);
30060Sstevel@tonic-gate 	(void) close(fd);
30070Sstevel@tonic-gate 	if (i)
30080Sstevel@tonic-gate 		_nderror = ND_OK;
30090Sstevel@tonic-gate 	else
30100Sstevel@tonic-gate 		free(*addrs);
30110Sstevel@tonic-gate 	return (i);
30120Sstevel@tonic-gate }
30130Sstevel@tonic-gate 
30140Sstevel@tonic-gate /*
30150Sstevel@tonic-gate  * This is lifted straight from libsocket/inet/inet_mkaddr.c.
30160Sstevel@tonic-gate  * Copied here to avoid our dependency on libsocket. More importantly,
30170Sstevel@tonic-gate  * to make sure partially static apps that use libnsl, but not
30180Sstevel@tonic-gate  * libsocket, don't get screwed up.
30190Sstevel@tonic-gate  * If you understand the above paragraph, try to get rid of
30200Sstevel@tonic-gate  * this copy of inet_makeaddr; if you don;t, leave it alone.
30210Sstevel@tonic-gate  *
30220Sstevel@tonic-gate  * Formulate an Internet address from network + host.  Used in
30230Sstevel@tonic-gate  * building addresses stored in the ifnet structure.
30240Sstevel@tonic-gate  */
30250Sstevel@tonic-gate static struct in_addr
_inet_makeaddr(in_addr_t net,in_addr_t host)30260Sstevel@tonic-gate _inet_makeaddr(in_addr_t net, in_addr_t host)
30270Sstevel@tonic-gate {
30280Sstevel@tonic-gate 	in_addr_t addr;
30290Sstevel@tonic-gate 	struct in_addr inaddr;
30300Sstevel@tonic-gate 
30310Sstevel@tonic-gate 	if (net < 128)
30320Sstevel@tonic-gate 		addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST);
30330Sstevel@tonic-gate 	else if (net < 65536)
30340Sstevel@tonic-gate 		addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST);
30350Sstevel@tonic-gate 	else if (net < 16777216L)
30360Sstevel@tonic-gate 		addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST);
30370Sstevel@tonic-gate 	else
30380Sstevel@tonic-gate 		addr = net | host;
30390Sstevel@tonic-gate 	inaddr.s_addr = htonl(addr);
30400Sstevel@tonic-gate 	return (inaddr);
30410Sstevel@tonic-gate }
30420Sstevel@tonic-gate 
30430Sstevel@tonic-gate /*
30440Sstevel@tonic-gate  * Routine to read the default configuration file and check if SORT_ADDRS
30450Sstevel@tonic-gate  * is set to NO or FALSE. This routine is called by order_haddrlist_af()
30460Sstevel@tonic-gate  * to determine if the addresses need to be sorted.
30470Sstevel@tonic-gate  */
30480Sstevel@tonic-gate static boolean_t
_read_nsw_file(void)30490Sstevel@tonic-gate _read_nsw_file(void)
30500Sstevel@tonic-gate {
30510Sstevel@tonic-gate 	char	defval[LINESIZE];
30521914Scasper 	FILE	*defl;
30530Sstevel@tonic-gate 	boolean_t	nosort = B_FALSE;
30540Sstevel@tonic-gate 
30550Sstevel@tonic-gate 
30560Sstevel@tonic-gate 	do {
30571914Scasper 		defl = fopen(__NSW_DEFAULT_FILE, "rF");
30580Sstevel@tonic-gate 	} while ((defl == NULL) && (errno == EINTR));
30590Sstevel@tonic-gate 
30600Sstevel@tonic-gate 	if (defl == NULL)
30610Sstevel@tonic-gate 		return (B_FALSE);
30620Sstevel@tonic-gate 
30631914Scasper 	while (fgets(defval, sizeof (defval), defl) != NULL) {
30640Sstevel@tonic-gate 		if ((strncmp(DONT_SORT, defval, sizeof (DONT_SORT) - 1) == 0) ||
30650Sstevel@tonic-gate 		    (strncmp(DONT_SORT2, defval,
3066*7752SMichen.Chang@Sun.COM 		    sizeof (DONT_SORT2) - 1) == 0)) {
30670Sstevel@tonic-gate 			nosort = B_TRUE;
30680Sstevel@tonic-gate 			break;
30690Sstevel@tonic-gate 		}
30700Sstevel@tonic-gate 	}
30711914Scasper 	(void) fclose(defl);
30720Sstevel@tonic-gate 	return (nosort);
30730Sstevel@tonic-gate }
3074