17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5004388ebScasper  * Common Development and Distribution License (the "License").
6004388ebScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2161961e0fSrobinson 
227c478bd9Sstevel@tonic-gate /*
23ba2b2c94SVitaliy Gusev  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
246392794bSMichen Chang  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
26*d81a47b3SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
276c740c0aSraf  */
286c740c0aSraf 
296c740c0aSraf /*
307c478bd9Sstevel@tonic-gate  * This is where we have chosen to combine every useful bit of code for
317c478bd9Sstevel@tonic-gate  * all the Solaris frontends to lookup hosts, services, and netdir information
327c478bd9Sstevel@tonic-gate  * for inet family (udp, tcp) transports. gethostbyYY(), getservbyYY(), and
337c478bd9Sstevel@tonic-gate  * netdir_getbyYY() are all implemented on top of this code. Similarly,
347c478bd9Sstevel@tonic-gate  * netdir_options, taddr2uaddr, and uaddr2taddr for inet transports also
357c478bd9Sstevel@tonic-gate  * find a home here.
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * If the netconfig structure supplied has NO nametoaddr libs (i.e. a "-"
387c478bd9Sstevel@tonic-gate  * in /etc/netconfig), this code calls the name service switch, and
397c478bd9Sstevel@tonic-gate  * therefore, /etc/nsswitch.conf is effectively the only place that
407c478bd9Sstevel@tonic-gate  * dictates hosts/serv lookup policy.
417c478bd9Sstevel@tonic-gate  * If an administrator chooses to bypass the name service switch by
427c478bd9Sstevel@tonic-gate  * specifying third party supplied nametoaddr libs in /etc/netconfig, this
437c478bd9Sstevel@tonic-gate  * implementation does NOT call the name service switch, it merely loops
447c478bd9Sstevel@tonic-gate  * through the nametoaddr libs. In this case, if this code was called
457c478bd9Sstevel@tonic-gate  * from gethost/servbyYY() we marshal the inet specific struct into
467c478bd9Sstevel@tonic-gate  * transport independent netbuf or hostserv, and unmarshal the resulting
477c478bd9Sstevel@tonic-gate  * nd_addrlist or hostservlist back into hostent and servent, as the case
487c478bd9Sstevel@tonic-gate  * may be.
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  * Goes without saying that most of the future bugs in gethost/servbyYY
517c478bd9Sstevel@tonic-gate  * and netdir_getbyYY are lurking somewhere here.
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #include "mt.h"
557c478bd9Sstevel@tonic-gate #include <ctype.h>
567c478bd9Sstevel@tonic-gate #include <stdio.h>
577c478bd9Sstevel@tonic-gate #include <stdlib.h>
587c478bd9Sstevel@tonic-gate #include <string.h>
597c478bd9Sstevel@tonic-gate #include <unistd.h>
607c478bd9Sstevel@tonic-gate #include <stropts.h>
617c478bd9Sstevel@tonic-gate #include <sys/types.h>
627c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
637c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
647c478bd9Sstevel@tonic-gate #include <sys/param.h>
657c478bd9Sstevel@tonic-gate #include <sys/time.h>
667c478bd9Sstevel@tonic-gate #include <errno.h>
677c478bd9Sstevel@tonic-gate #include <fcntl.h>
687c478bd9Sstevel@tonic-gate #include <thread.h>
697c478bd9Sstevel@tonic-gate #include <synch.h>
707c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
717c478bd9Sstevel@tonic-gate #include <netdb.h>
727c478bd9Sstevel@tonic-gate #include <netconfig.h>
737c478bd9Sstevel@tonic-gate #include <netdir.h>
747c478bd9Sstevel@tonic-gate #include <tiuser.h>
757c478bd9Sstevel@tonic-gate #include <sys/socket.h>
767c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
777c478bd9Sstevel@tonic-gate #include <netinet/in.h>
787c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
797c478bd9Sstevel@tonic-gate #include <net/if.h>
807c478bd9Sstevel@tonic-gate #include <inet/ip.h>
817c478bd9Sstevel@tonic-gate #include <inet/ip6_asp.h>
827c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
837c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
847c478bd9Sstevel@tonic-gate #include <nss_netdir.h>
857c478bd9Sstevel@tonic-gate #include <syslog.h>
867c478bd9Sstevel@tonic-gate #include <nsswitch.h>
877c478bd9Sstevel@tonic-gate #include "nss.h"
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate #define	MAXIFS 32
907c478bd9Sstevel@tonic-gate #define	UDPDEV	"/dev/udp"
917c478bd9Sstevel@tonic-gate #define	UDP6DEV	"/dev/udp6"
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate #define	DOOR_GETHOSTBYNAME_R	_switch_gethostbyname_r
947c478bd9Sstevel@tonic-gate #define	DOOR_GETHOSTBYADDR_R	_switch_gethostbyaddr_r
957c478bd9Sstevel@tonic-gate #define	DOOR_GETIPNODEBYNAME_R	_switch_getipnodebyname_r
967c478bd9Sstevel@tonic-gate #define	DOOR_GETIPNODEBYADDR_R	_switch_getipnodebyaddr_r
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate #define	DONT_SORT	"SORT_ADDRS=NO"
997c478bd9Sstevel@tonic-gate #define	DONT_SORT2	"SORT_ADDRS=FALSE"
1007c478bd9Sstevel@tonic-gate #define	LINESIZE	100
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  * constant values of addresses for HOST_SELF_BIND, HOST_SELF_CONNECT
1047c478bd9Sstevel@tonic-gate  * and localhost.
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * The following variables are static to the extent that they should
1077c478bd9Sstevel@tonic-gate  * not be visible outside of this file.
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate static char *localaddr[] = {"\000\000\000\000", NULL};
1107c478bd9Sstevel@tonic-gate static char *connectaddr[] = {"\177\000\000\001", NULL};
1117c478bd9Sstevel@tonic-gate static char *localaddr6[] =
1127c478bd9Sstevel@tonic-gate {"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", NULL};
1137c478bd9Sstevel@tonic-gate static char *connectaddr6[] =
1147c478bd9Sstevel@tonic-gate {"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001", NULL};
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate /* IPv4 nd_addrlist */
1177c478bd9Sstevel@tonic-gate static mutex_t	nd_addr_lock = DEFAULTMUTEX;
1187c478bd9Sstevel@tonic-gate static struct sockaddr_in sa_con;
1197c478bd9Sstevel@tonic-gate static struct netbuf nd_conbuf = {sizeof (sa_con),\
1207c478bd9Sstevel@tonic-gate     sizeof (sa_con), (char *)&sa_con};
1217c478bd9Sstevel@tonic-gate static struct nd_addrlist nd_conaddrlist = {1, &nd_conbuf};
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate /* IPv6 nd_addrlist */
1247c478bd9Sstevel@tonic-gate static mutex_t	nd6_addr_lock = DEFAULTMUTEX;
1257c478bd9Sstevel@tonic-gate static struct sockaddr_in6 sa6_con;
1267c478bd9Sstevel@tonic-gate static struct netbuf nd6_conbuf = {sizeof (sa6_con),\
1277c478bd9Sstevel@tonic-gate 	sizeof (sa6_con), (char *)&sa6_con};
1287c478bd9Sstevel@tonic-gate static struct nd_addrlist nd6_conaddrlist = {1, &nd6_conbuf};
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate #define	LOCALHOST "localhost"
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate struct servent *_switch_getservbyname_r(const char *, const char *,
1337c478bd9Sstevel@tonic-gate     struct servent *, char *, int);
1347c478bd9Sstevel@tonic-gate struct servent *_switch_getservbyport_r(int, const char *, struct servent *,
1357c478bd9Sstevel@tonic-gate     char *, int);
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate static int __herrno2netdir(int h_errnop);
1387c478bd9Sstevel@tonic-gate static struct ifinfo *get_local_info(void);
1397c478bd9Sstevel@tonic-gate static int getbroadcastnets(struct netconfig *, struct in_addr **);
1407c478bd9Sstevel@tonic-gate static int hent2ndaddr(int, char **, int *, struct nd_addrlist **);
1417c478bd9Sstevel@tonic-gate static int ndaddr2hent(int, const char *, struct nd_addrlist *,
1427c478bd9Sstevel@tonic-gate     struct hostent *, char *, int);
1437c478bd9Sstevel@tonic-gate static int hsents2ndhostservs(struct hostent *, struct servent *, ushort_t,
1447c478bd9Sstevel@tonic-gate     struct nd_hostservlist **);
1457c478bd9Sstevel@tonic-gate static int ndaddr2srent(const char *, const char *, ushort_t, struct servent *,
1467c478bd9Sstevel@tonic-gate     char *, int);
1477c478bd9Sstevel@tonic-gate static int ndhostserv2hent(struct netbuf *, struct nd_hostservlist *,
1487c478bd9Sstevel@tonic-gate     struct hostent *, char *, int);
1497c478bd9Sstevel@tonic-gate static int ndhostserv2srent(int, const char *, struct nd_hostservlist *,
1507c478bd9Sstevel@tonic-gate     struct servent *, char *, int);
1517c478bd9Sstevel@tonic-gate static int nd2herrno(int nerr);
1527c478bd9Sstevel@tonic-gate static void order_haddrlist_inet(char **haddrlist, size_t addrcount);
1537c478bd9Sstevel@tonic-gate static void order_haddrlist_inet6(char **haddrlist, size_t addrcount);
1547c478bd9Sstevel@tonic-gate static int dstcmp(const void *, const void *);
1557c478bd9Sstevel@tonic-gate static int nss_strioctl(int af, int cmd, void *ptr, int ilen);
1567c478bd9Sstevel@tonic-gate static struct in_addr _inet_makeaddr(in_addr_t, in_addr_t);
1577c478bd9Sstevel@tonic-gate static boolean_t _read_nsw_file(void);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate  * Begin: PART I
1617c478bd9Sstevel@tonic-gate  * Top Level Interfaces that gethost/serv/netdir funnel through.
1627c478bd9Sstevel@tonic-gate  */
1637c478bd9Sstevel@tonic-gate 
164*d81a47b3SMilan Jurik static int
inetdir_free(int ret,struct in_addr * inaddrs,char ** baddrlist)165*d81a47b3SMilan Jurik inetdir_free(int ret, struct in_addr *inaddrs, char **baddrlist)
166*d81a47b3SMilan Jurik {
167*d81a47b3SMilan Jurik 	if (inaddrs)
168*d81a47b3SMilan Jurik 		free(inaddrs);
169*d81a47b3SMilan Jurik 	if (baddrlist)
170*d81a47b3SMilan Jurik 		free(baddrlist);
171*d81a47b3SMilan Jurik 	_nderror = ret;
172*d81a47b3SMilan Jurik 	return (ret);
173*d81a47b3SMilan Jurik }
174*d81a47b3SMilan Jurik 
1757c478bd9Sstevel@tonic-gate /*
1767c478bd9Sstevel@tonic-gate  * gethost/servbyname always call this function; if they call
1777c478bd9Sstevel@tonic-gate  * with nametoaddr libs in nconf, we call netdir_getbyname
1787c478bd9Sstevel@tonic-gate  * implementation: __classic_netdir_getbyname, otherwise nsswitch.
1797c478bd9Sstevel@tonic-gate  *
1807c478bd9Sstevel@tonic-gate  * netdir_getbyname calls this only if nametoaddr libs are NOT
1817c478bd9Sstevel@tonic-gate  * specified for inet transports; i.e. it's supposed to follow
1827c478bd9Sstevel@tonic-gate  * the name service switch.
1837c478bd9Sstevel@tonic-gate  */
1847c478bd9Sstevel@tonic-gate int
_get_hostserv_inetnetdir_byname(struct netconfig * nconf,struct nss_netdirbyname_in * args,union nss_netdirbyname_out * res)1857c478bd9Sstevel@tonic-gate _get_hostserv_inetnetdir_byname(struct netconfig *nconf,
1867c478bd9Sstevel@tonic-gate     struct nss_netdirbyname_in *args, union nss_netdirbyname_out *res)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate 	int	server_port;
1897c478bd9Sstevel@tonic-gate 	int *servp = &server_port;
1907c478bd9Sstevel@tonic-gate 	char	**haddrlist;
1917c478bd9Sstevel@tonic-gate 	uint32_t dotnameaddr;
1927c478bd9Sstevel@tonic-gate 	char	*dotnamelist[2];
1937c478bd9Sstevel@tonic-gate 	struct in_addr	*inaddrs = NULL;
1947c478bd9Sstevel@tonic-gate 	struct in6_addr	v6nameaddr;
1957c478bd9Sstevel@tonic-gate 	char	**baddrlist = NULL;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	if (nconf == NULL) {
1987c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
1997c478bd9Sstevel@tonic-gate 		return (ND_BADARG);
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	/*
2037c478bd9Sstevel@tonic-gate 	 * 1. gethostbyname()/netdir_getbyname() special cases:
2047c478bd9Sstevel@tonic-gate 	 */
2057c478bd9Sstevel@tonic-gate 	switch (args->op_t) {
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 		case NSS_HOST:
2087c478bd9Sstevel@tonic-gate 		/*
2097c478bd9Sstevel@tonic-gate 		 * Worth the performance gain -- assuming a lot of inet apps
2107c478bd9Sstevel@tonic-gate 		 * actively use "localhost".
2117c478bd9Sstevel@tonic-gate 		 */
2127c478bd9Sstevel@tonic-gate 		if (strcmp(args->arg.nss.host.name, LOCALHOST) == 0) {
2137c478bd9Sstevel@tonic-gate 
21461961e0fSrobinson 			(void) mutex_lock(&nd_addr_lock);
2157c478bd9Sstevel@tonic-gate 			IN_SET_LOOPBACK_ADDR(&sa_con);
2167c478bd9Sstevel@tonic-gate 			_nderror = ndaddr2hent(AF_INET, args->arg.nss.host.name,
2177c478bd9Sstevel@tonic-gate 			    &nd_conaddrlist, res->nss.host.hent,
2187c478bd9Sstevel@tonic-gate 			    args->arg.nss.host.buf,
2197c478bd9Sstevel@tonic-gate 			    args->arg.nss.host.buflen);
22061961e0fSrobinson 			(void) mutex_unlock(&nd_addr_lock);
2217c478bd9Sstevel@tonic-gate 			if (_nderror != ND_OK)
2227c478bd9Sstevel@tonic-gate 				*(res->nss.host.herrno_p) =
2237c478bd9Sstevel@tonic-gate 				    nd2herrno(_nderror);
2247c478bd9Sstevel@tonic-gate 			return (_nderror);
2257c478bd9Sstevel@tonic-gate 		}
2267c478bd9Sstevel@tonic-gate 		/*
2277c478bd9Sstevel@tonic-gate 		 * If the caller passed in a dot separated IP notation to
2287c478bd9Sstevel@tonic-gate 		 * gethostbyname, return that back as the address.
2297c478bd9Sstevel@tonic-gate 		 * The nd_addr_lock mutex was added to be truely re-entrant.
2307c478bd9Sstevel@tonic-gate 		 */
2316c740c0aSraf 		if (inet_aton(args->arg.nss.host.name,
2327c478bd9Sstevel@tonic-gate 		    (struct in_addr *)&dotnameaddr)) {
23361961e0fSrobinson 			(void) mutex_lock(&nd_addr_lock);
23461961e0fSrobinson 			(void) memset(&sa_con, 0, sizeof (sa_con));
2357c478bd9Sstevel@tonic-gate 			sa_con.sin_family = AF_INET;
2367c478bd9Sstevel@tonic-gate 			sa_con.sin_addr.s_addr = dotnameaddr;
2377c478bd9Sstevel@tonic-gate 			_nderror = ndaddr2hent(AF_INET, args->arg.nss.host.name,
2387c478bd9Sstevel@tonic-gate 			    &nd_conaddrlist, res->nss.host.hent,
2397c478bd9Sstevel@tonic-gate 			    args->arg.nss.host.buf,
2407c478bd9Sstevel@tonic-gate 			    args->arg.nss.host.buflen);
24161961e0fSrobinson 			(void) mutex_unlock(&nd_addr_lock);
2427c478bd9Sstevel@tonic-gate 			if (_nderror != ND_OK)
2437c478bd9Sstevel@tonic-gate 				*(res->nss.host.herrno_p) =
2447c478bd9Sstevel@tonic-gate 				    nd2herrno(_nderror);
2457c478bd9Sstevel@tonic-gate 			return (_nderror);
2467c478bd9Sstevel@tonic-gate 		}
2477c478bd9Sstevel@tonic-gate 		break;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		case NSS_HOST6:
2507c478bd9Sstevel@tonic-gate 		/*
2517c478bd9Sstevel@tonic-gate 		 * Handle case of literal address string.
2527c478bd9Sstevel@tonic-gate 		 */
2537c478bd9Sstevel@tonic-gate 		if (strchr(args->arg.nss.host6.name, ':') != NULL &&
2547c478bd9Sstevel@tonic-gate 		    (inet_pton(AF_INET6, args->arg.nss.host6.name,
2557c478bd9Sstevel@tonic-gate 		    &v6nameaddr) != 0)) {
2567c478bd9Sstevel@tonic-gate 			int	ret;
2577c478bd9Sstevel@tonic-gate 
25861961e0fSrobinson 			(void) mutex_lock(&nd6_addr_lock);
25961961e0fSrobinson 			(void) memset(&sa6_con, 0, sizeof (sa6_con));
2607c478bd9Sstevel@tonic-gate 			sa6_con.sin6_family = AF_INET6;
26161961e0fSrobinson 			(void) memcpy(&(sa6_con.sin6_addr.s6_addr),
2627c478bd9Sstevel@tonic-gate 			    &v6nameaddr, sizeof (struct in6_addr));
2637c478bd9Sstevel@tonic-gate 			ret = ndaddr2hent(AF_INET6,
2647c478bd9Sstevel@tonic-gate 			    args->arg.nss.host6.name,
2657c478bd9Sstevel@tonic-gate 			    &nd6_conaddrlist, res->nss.host.hent,
2667c478bd9Sstevel@tonic-gate 			    args->arg.nss.host6.buf,
2677c478bd9Sstevel@tonic-gate 			    args->arg.nss.host6.buflen);
26861961e0fSrobinson 			(void) mutex_unlock(&nd6_addr_lock);
2697c478bd9Sstevel@tonic-gate 			if (ret != ND_OK)
2707c478bd9Sstevel@tonic-gate 				*(res->nss.host.herrno_p) = nd2herrno(ret);
2717c478bd9Sstevel@tonic-gate 			else
2727c478bd9Sstevel@tonic-gate 				res->nss.host.hent->h_aliases = NULL;
2737c478bd9Sstevel@tonic-gate 			return (ret);
2747c478bd9Sstevel@tonic-gate 		}
2757c478bd9Sstevel@tonic-gate 		break;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 		case NETDIR_BY:
2787c478bd9Sstevel@tonic-gate 			if (args->arg.nd_hs == 0) {
2797c478bd9Sstevel@tonic-gate 				_nderror = ND_BADARG;
2807c478bd9Sstevel@tonic-gate 				return (ND_BADARG);
2817c478bd9Sstevel@tonic-gate 			}
2827c478bd9Sstevel@tonic-gate 			/*
2837c478bd9Sstevel@tonic-gate 			 * If servname is NULL, return 0 as the port number
2847c478bd9Sstevel@tonic-gate 			 * If servname is rpcbind, return 111 as the port number
2857c478bd9Sstevel@tonic-gate 			 * If servname is a number, return it back as the port
2867c478bd9Sstevel@tonic-gate 			 * number.
2877c478bd9Sstevel@tonic-gate 			 */
2887c478bd9Sstevel@tonic-gate 			if (args->arg.nd_hs->h_serv == 0) {
2897c478bd9Sstevel@tonic-gate 				*servp = htons(0);
2906392794bSMichen Chang 			} else if (strcmp(args->arg.nd_hs->h_serv,
2916392794bSMichen Chang 			    "rpcbind") == 0) {
2927c478bd9Sstevel@tonic-gate 				*servp = htons(111);
2936392794bSMichen Chang 			} else if (strspn(args->arg.nd_hs->h_serv,
2946392794bSMichen Chang 			    "0123456789") ==
2956392794bSMichen Chang 			    strlen(args->arg.nd_hs->h_serv)) {
2967c478bd9Sstevel@tonic-gate 				*servp = htons(atoi(args->arg.nd_hs->h_serv));
2977c478bd9Sstevel@tonic-gate 			} else {
2987c478bd9Sstevel@tonic-gate 				/* i.e. need to call a name service on this */
2997c478bd9Sstevel@tonic-gate 				servp = NULL;
3007c478bd9Sstevel@tonic-gate 			}
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 			/*
3037c478bd9Sstevel@tonic-gate 			 * If the hostname is HOST_SELF_BIND, we return 0.0.0.0
3047c478bd9Sstevel@tonic-gate 			 * so the  binding can be contacted through all
3057c478bd9Sstevel@tonic-gate 			 * interfaces. If the hostname is HOST_SELF_CONNECT,
3067c478bd9Sstevel@tonic-gate 			 * we return 127.0.0.1 so the address can be connected
3077c478bd9Sstevel@tonic-gate 			 * to locally. If the hostname is HOST_ANY, we return
3087c478bd9Sstevel@tonic-gate 			 * no addresses because IP doesn't know how to specify
3097c478bd9Sstevel@tonic-gate 			 * a service without a host. And finally if we specify
3107c478bd9Sstevel@tonic-gate 			 * HOST_BROADCAST then we ask a tli fd to tell us what
3117c478bd9Sstevel@tonic-gate 			 * the broadcast addresses are for any udp
3127c478bd9Sstevel@tonic-gate 			 * interfaces on this machine.
3137c478bd9Sstevel@tonic-gate 			 */
3147c478bd9Sstevel@tonic-gate 			if (args->arg.nd_hs->h_host == 0) {
3157c478bd9Sstevel@tonic-gate 				_nderror = ND_NOHOST;
3167c478bd9Sstevel@tonic-gate 				return (ND_NOHOST);
3177c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
3187c478bd9Sstevel@tonic-gate 			    HOST_SELF_BIND) == 0)) {
3197c478bd9Sstevel@tonic-gate 				haddrlist = localaddr;
3207c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
3216392794bSMichen Chang 			    HOST_SELF_CONNECT) == 0)) {
3227c478bd9Sstevel@tonic-gate 				haddrlist = connectaddr;
3237c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
3246392794bSMichen Chang 			    LOCALHOST) == 0)) {
3257c478bd9Sstevel@tonic-gate 				haddrlist = connectaddr;
3267c478bd9Sstevel@tonic-gate 			} else if ((int)(dotnameaddr =
3276392794bSMichen Chang 			    inet_addr(args->arg.nd_hs->h_host)) != -1) {
3287c478bd9Sstevel@tonic-gate 				/*
3297c478bd9Sstevel@tonic-gate 				 * If the caller passed in a dot separated IP
3307c478bd9Sstevel@tonic-gate 				 * notation to netdir_getbyname, convert that
3317c478bd9Sstevel@tonic-gate 				 * back into address.
3327c478bd9Sstevel@tonic-gate 				 */
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 				dotnamelist[0] = (char *)&dotnameaddr;
3357c478bd9Sstevel@tonic-gate 				dotnamelist[1] = NULL;
3367c478bd9Sstevel@tonic-gate 				haddrlist = dotnamelist;
3377c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
3386392794bSMichen Chang 			    HOST_BROADCAST) == 0)) {
3397c478bd9Sstevel@tonic-gate 				/*
3407c478bd9Sstevel@tonic-gate 				 * Now that inaddrs and baddrlist are
3417c478bd9Sstevel@tonic-gate 				 * dynamically allocated, care must be
3427c478bd9Sstevel@tonic-gate 				 * taken in freeing up the
3437c478bd9Sstevel@tonic-gate 				 * memory at each 'return()' point.
3447c478bd9Sstevel@tonic-gate 				 *
3457c478bd9Sstevel@tonic-gate 				 * Early return protection (using
346*d81a47b3SMilan Jurik 				 * inetdir_free()) is needed only in NETDIR_BY
3477c478bd9Sstevel@tonic-gate 				 * cases because dynamic allocation is used
3487c478bd9Sstevel@tonic-gate 				 * when args->op_t == NETDIR_BY.
3497c478bd9Sstevel@tonic-gate 				 *
3507c478bd9Sstevel@tonic-gate 				 * Early return protection is not needed in
3517c478bd9Sstevel@tonic-gate 				 * haddrlist==0 conditionals because dynamic
3527c478bd9Sstevel@tonic-gate 				 * allocation guarantees haddrlist!=0.
3537c478bd9Sstevel@tonic-gate 				 *
3547c478bd9Sstevel@tonic-gate 				 * Early return protection is not needed in most
3557c478bd9Sstevel@tonic-gate 				 * servp!=0 conditionals because this is handled
3567c478bd9Sstevel@tonic-gate 				 * (and returned) first.
3577c478bd9Sstevel@tonic-gate 				 */
3587c478bd9Sstevel@tonic-gate 				int i, bnets;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 				bnets = getbroadcastnets(nconf, &inaddrs);
3617c478bd9Sstevel@tonic-gate 				if (bnets == 0) {
3627c478bd9Sstevel@tonic-gate 					_nderror = ND_NOHOST;
3637c478bd9Sstevel@tonic-gate 					return (ND_NOHOST);
3647c478bd9Sstevel@tonic-gate 				}
36561961e0fSrobinson 				baddrlist = malloc((bnets+1)*sizeof (char *));
3667c478bd9Sstevel@tonic-gate 				if (baddrlist == NULL)
367*d81a47b3SMilan Jurik 					return (inetdir_free(ND_NOMEM, inaddrs,
368*d81a47b3SMilan Jurik 					    baddrlist));
3697c478bd9Sstevel@tonic-gate 				for (i = 0; i < bnets; i++)
3707c478bd9Sstevel@tonic-gate 					baddrlist[i] = (char *)&inaddrs[i];
3717c478bd9Sstevel@tonic-gate 				baddrlist[i] = NULL;
3727c478bd9Sstevel@tonic-gate 				haddrlist = baddrlist;
3737c478bd9Sstevel@tonic-gate 			} else {
3747c478bd9Sstevel@tonic-gate 				/* i.e. need to call a name service on this */
3757c478bd9Sstevel@tonic-gate 				haddrlist = 0;
3767c478bd9Sstevel@tonic-gate 			}
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 			if (haddrlist && servp) {
3797c478bd9Sstevel@tonic-gate 				int ret;
3807c478bd9Sstevel@tonic-gate 				/*
3817c478bd9Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
3827c478bd9Sstevel@tonic-gate 				 * malloc's will be done, freed using
3837c478bd9Sstevel@tonic-gate 				 * netdir_free.
3847c478bd9Sstevel@tonic-gate 				 */
3857c478bd9Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET, haddrlist, servp,
3866392794bSMichen Chang 				    res->nd_alist);
387*d81a47b3SMilan Jurik 				return (inetdir_free(ret, inaddrs, baddrlist));
3886392794bSMichen Chang 			}
3897c478bd9Sstevel@tonic-gate 			break;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 		case NETDIR_BY6:
3937c478bd9Sstevel@tonic-gate 			if (args->arg.nd_hs == 0) {
3947c478bd9Sstevel@tonic-gate 				_nderror = ND_BADARG;
3957c478bd9Sstevel@tonic-gate 				return (ND_BADARG);
3967c478bd9Sstevel@tonic-gate 			}
3977c478bd9Sstevel@tonic-gate 			/*
3987c478bd9Sstevel@tonic-gate 			 * If servname is NULL, return 0 as the port number.
3997c478bd9Sstevel@tonic-gate 			 * If servname is rpcbind, return 111 as the port number
4007c478bd9Sstevel@tonic-gate 			 * If servname is a number, return it back as the port
4017c478bd9Sstevel@tonic-gate 			 * number.
4027c478bd9Sstevel@tonic-gate 			 */
4037c478bd9Sstevel@tonic-gate 			if (args->arg.nd_hs->h_serv == 0) {
4047c478bd9Sstevel@tonic-gate 				*servp = htons(0);
4057c478bd9Sstevel@tonic-gate 			} else if (strcmp(args->arg.nd_hs->h_serv,
4066392794bSMichen Chang 			    "rpcbind") == 0) {
4077c478bd9Sstevel@tonic-gate 				*servp = htons(111);
4087c478bd9Sstevel@tonic-gate 			} else if (strspn(args->arg.nd_hs->h_serv, "0123456789")
4096392794bSMichen Chang 			    == strlen(args->arg.nd_hs->h_serv)) {
4107c478bd9Sstevel@tonic-gate 				*servp = htons(atoi(args->arg.nd_hs->h_serv));
4117c478bd9Sstevel@tonic-gate 			} else {
4127c478bd9Sstevel@tonic-gate 				/* i.e. need to call a name service on this */
4137c478bd9Sstevel@tonic-gate 				servp = NULL;
4147c478bd9Sstevel@tonic-gate 			}
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 			/*
4177c478bd9Sstevel@tonic-gate 			 * If the hostname is HOST_SELF_BIND, we return ipv6
4187c478bd9Sstevel@tonic-gate 			 * localaddress so the binding can be contacted through
4197c478bd9Sstevel@tonic-gate 			 * all interfaces.
4207c478bd9Sstevel@tonic-gate 			 * If the hostname is HOST_SELF_CONNECT, we return
4217c478bd9Sstevel@tonic-gate 			 * ipv6 loopback address so the address can be connected
4227c478bd9Sstevel@tonic-gate 			 * to locally.
4237c478bd9Sstevel@tonic-gate 			 * If the hostname is HOST_ANY, we return no addresses
4247c478bd9Sstevel@tonic-gate 			 * because IP doesn't know how to specify a service
4257c478bd9Sstevel@tonic-gate 			 * without a host.
4267c478bd9Sstevel@tonic-gate 			 * And finally if we specify HOST_BROADCAST then we
4277c478bd9Sstevel@tonic-gate 			 * disallow since IPV6 does not have any
4287c478bd9Sstevel@tonic-gate 			 * broadcast concept.
4297c478bd9Sstevel@tonic-gate 			 */
4307c478bd9Sstevel@tonic-gate 			if (args->arg.nd_hs->h_host == 0) {
4317c478bd9Sstevel@tonic-gate 				return (ND_NOHOST);
4327c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
4336392794bSMichen Chang 			    HOST_SELF_BIND) == 0)) {
4347c478bd9Sstevel@tonic-gate 				haddrlist = localaddr6;
4357c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
4366392794bSMichen Chang 			    HOST_SELF_CONNECT) == 0)) {
4377c478bd9Sstevel@tonic-gate 				haddrlist = connectaddr6;
4387c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
4396392794bSMichen Chang 			    LOCALHOST) == 0)) {
4407c478bd9Sstevel@tonic-gate 				haddrlist = connectaddr6;
4417c478bd9Sstevel@tonic-gate 			} else if (strchr(args->arg.nd_hs->h_host, ':')
4426392794bSMichen Chang 			    != NULL) {
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 			/*
4457c478bd9Sstevel@tonic-gate 			 * If the caller passed in a dot separated IP notation
4467c478bd9Sstevel@tonic-gate 			 * to netdir_getbyname, convert that back into address.
4477c478bd9Sstevel@tonic-gate 			 */
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 				if ((inet_pton(AF_INET6,
4506392794bSMichen Chang 				    args->arg.nd_hs->h_host,
4516392794bSMichen Chang 				    &v6nameaddr)) != 0) {
4527c478bd9Sstevel@tonic-gate 					dotnamelist[0] = (char *)&v6nameaddr;
4537c478bd9Sstevel@tonic-gate 					dotnamelist[1] = NULL;
4547c478bd9Sstevel@tonic-gate 					haddrlist = dotnamelist;
4557c478bd9Sstevel@tonic-gate 				}
4567c478bd9Sstevel@tonic-gate 				else
4577c478bd9Sstevel@tonic-gate 					/* not sure what to return */
4587c478bd9Sstevel@tonic-gate 					return (ND_NOHOST);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 			} else if ((strcmp(args->arg.nd_hs->h_host,
4616392794bSMichen Chang 			    HOST_BROADCAST) == 0)) {
4627c478bd9Sstevel@tonic-gate 				/*
4637c478bd9Sstevel@tonic-gate 				 * Don't support broadcast in
4647c478bd9Sstevel@tonic-gate 				 * IPV6
4657c478bd9Sstevel@tonic-gate 				 */
4667c478bd9Sstevel@tonic-gate 				return (ND_NOHOST);
4677c478bd9Sstevel@tonic-gate 			} else {
4687c478bd9Sstevel@tonic-gate 				/* i.e. need to call a name service on this */
4697c478bd9Sstevel@tonic-gate 				haddrlist = 0;
4707c478bd9Sstevel@tonic-gate 			}
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 			if (haddrlist && servp) {
4737c478bd9Sstevel@tonic-gate 				int ret;
4747c478bd9Sstevel@tonic-gate 				/*
4757c478bd9Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
4767c478bd9Sstevel@tonic-gate 				 * malloc's will be done, freed
4777c478bd9Sstevel@tonic-gate 				 * using netdir_free.
4787c478bd9Sstevel@tonic-gate 				 */
4797c478bd9Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET6, haddrlist,
4807c478bd9Sstevel@tonic-gate 				    servp, res->nd_alist);
481*d81a47b3SMilan Jurik 				return (inetdir_free(ret, inaddrs, baddrlist));
4826392794bSMichen Chang 			}
4837c478bd9Sstevel@tonic-gate 			break;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	}
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	/*
4897c478bd9Sstevel@tonic-gate 	 * 2. Most common scenario. This is the way we ship /etc/netconfig.
4907c478bd9Sstevel@tonic-gate 	 *    Emphasis on improving performance in the "if" part.
4917c478bd9Sstevel@tonic-gate 	 */
4927c478bd9Sstevel@tonic-gate 	if (nconf->nc_nlookups == 0) {
4937c478bd9Sstevel@tonic-gate 		struct hostent	*he = NULL, *tmphe;
4947c478bd9Sstevel@tonic-gate 		struct servent	*se;
4957c478bd9Sstevel@tonic-gate 		int	ret;
4967c478bd9Sstevel@tonic-gate 		nss_XbyY_buf_t	*ndbuf4switch = 0;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	switch (args->op_t) {
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 		case NSS_HOST:
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 		he = DOOR_GETHOSTBYNAME_R(args->arg.nss.host.name,
5037c478bd9Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
5047c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.buflen,
5057c478bd9Sstevel@tonic-gate 		    res->nss.host.herrno_p);
5067c478bd9Sstevel@tonic-gate 		if (he == NULL)
5077c478bd9Sstevel@tonic-gate 			return (_nderror = ND_NOHOST);
5087c478bd9Sstevel@tonic-gate 		return (_nderror = ND_OK);
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 		case NSS_HOST6:
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 		he = DOOR_GETIPNODEBYNAME_R(args->arg.nss.host6.name,
5137c478bd9Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
5147c478bd9Sstevel@tonic-gate 		    args->arg.nss.host6.buflen,
5157c478bd9Sstevel@tonic-gate 		    args->arg.nss.host6.af_family,
5167c478bd9Sstevel@tonic-gate 		    args->arg.nss.host6.flags,
5177c478bd9Sstevel@tonic-gate 		    res->nss.host.herrno_p);
5187c478bd9Sstevel@tonic-gate 
51961961e0fSrobinson 		if (he == NULL)
5207c478bd9Sstevel@tonic-gate 			return (_nderror = ND_NOHOST);
5217c478bd9Sstevel@tonic-gate 		return (_nderror = ND_OK);
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 		case NSS_SERV:
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 		se = _switch_getservbyname_r(args->arg.nss.serv.name,
5267c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.proto,
5277c478bd9Sstevel@tonic-gate 		    res->nss.serv, args->arg.nss.serv.buf,
5287c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.buflen);
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 		_nderror = ND_OK;
5317c478bd9Sstevel@tonic-gate 		if (se == 0)
5327c478bd9Sstevel@tonic-gate 			_nderror = ND_NOSERV;
5337c478bd9Sstevel@tonic-gate 		return (_nderror);
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 		case NETDIR_BY:
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 		if (servp == 0) {
5386392794bSMichen Chang 			char	*proto = (strcmp(nconf->nc_proto,
5396392794bSMichen Chang 			    NC_TCP) == 0) ? NC_TCP : NC_UDP;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 			/*
5427c478bd9Sstevel@tonic-gate 			 * We go through all this for just one port number,
5437c478bd9Sstevel@tonic-gate 			 * which is most often constant. How about linking in
5447c478bd9Sstevel@tonic-gate 			 * an indexed database of well-known ports in the name
5457c478bd9Sstevel@tonic-gate 			 * of performance ?
5467c478bd9Sstevel@tonic-gate 			 */
54761961e0fSrobinson 			ndbuf4switch = _nss_XbyY_buf_alloc(
5486392794bSMichen Chang 			    sizeof (struct servent), NSS_BUFLEN_SERVICES);
5497c478bd9Sstevel@tonic-gate 			if (ndbuf4switch == 0)
550*d81a47b3SMilan Jurik 				return (inetdir_free(ND_NOMEM, inaddrs,
551*d81a47b3SMilan Jurik 				    baddrlist));
5527c478bd9Sstevel@tonic-gate 			se = _switch_getservbyname_r(args->arg.nd_hs->h_serv,
5536392794bSMichen Chang 			    proto, ndbuf4switch->result,
5546392794bSMichen Chang 			    ndbuf4switch->buffer, ndbuf4switch->buflen);
5557c478bd9Sstevel@tonic-gate 			if (!se) {
5567c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4switch);
557*d81a47b3SMilan Jurik 				return (inetdir_free(ND_NOSERV, inaddrs,
558*d81a47b3SMilan Jurik 				    baddrlist));
5597c478bd9Sstevel@tonic-gate 			}
5607c478bd9Sstevel@tonic-gate 			server_port = se->s_port;
5617c478bd9Sstevel@tonic-gate 			NSS_XbyY_FREE(&ndbuf4switch);
5627c478bd9Sstevel@tonic-gate 		}
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 		if (haddrlist == 0) {
5657c478bd9Sstevel@tonic-gate 			int	h_errnop = 0;
5667c478bd9Sstevel@tonic-gate 
56761961e0fSrobinson 			ndbuf4switch = _nss_XbyY_buf_alloc(
5686392794bSMichen Chang 			    sizeof (struct hostent),
5696392794bSMichen Chang 			    NSS_BUFLEN_HOSTS);
5707c478bd9Sstevel@tonic-gate 			if (ndbuf4switch == 0) {
5717c478bd9Sstevel@tonic-gate 				_nderror = ND_NOMEM;
5727c478bd9Sstevel@tonic-gate 				return (ND_NOMEM);
5737c478bd9Sstevel@tonic-gate 			}
5747c478bd9Sstevel@tonic-gate 			/*
5757c478bd9Sstevel@tonic-gate 			 * Search the ipnodes (v6) path first,
5767c478bd9Sstevel@tonic-gate 			 * search will return the v4 addresses
5777c478bd9Sstevel@tonic-gate 			 * as v4mapped addresses.
5787c478bd9Sstevel@tonic-gate 			 */
5797c478bd9Sstevel@tonic-gate 			if ((tmphe = DOOR_GETIPNODEBYNAME_R(
5807c478bd9Sstevel@tonic-gate 			    args->arg.nd_hs->h_host,
5817c478bd9Sstevel@tonic-gate 			    ndbuf4switch->result, ndbuf4switch->buffer,
5827c478bd9Sstevel@tonic-gate 			    ndbuf4switch->buflen, args->arg.nss.host6.af_family,
5837c478bd9Sstevel@tonic-gate 			    args->arg.nss.host6.flags, &h_errnop)) != NULL)
5847c478bd9Sstevel@tonic-gate 				he = __mappedtov4(tmphe, &h_errnop);
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 			if (he == NULL) {
5877c478bd9Sstevel@tonic-gate 				/* Failover case, try hosts db for v4 address */
5887c478bd9Sstevel@tonic-gate 				he = DOOR_GETHOSTBYNAME_R(
5896392794bSMichen Chang 				    args->arg.nd_hs->h_host,
5906392794bSMichen Chang 				    ndbuf4switch->result, ndbuf4switch->buffer,
5916392794bSMichen Chang 				    ndbuf4switch->buflen, &h_errnop);
5927c478bd9Sstevel@tonic-gate 				if (he == NULL) {
5937c478bd9Sstevel@tonic-gate 					NSS_XbyY_FREE(&ndbuf4switch);
594ba2b2c94SVitaliy Gusev 					_nderror = __herrno2netdir(h_errnop);
5957c478bd9Sstevel@tonic-gate 					return (_nderror);
5967c478bd9Sstevel@tonic-gate 				}
5977c478bd9Sstevel@tonic-gate 				/*
5987c478bd9Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
5997c478bd9Sstevel@tonic-gate 				 * malloc's will be done, freed using
6007c478bd9Sstevel@tonic-gate 				 * netdir_free.
6017c478bd9Sstevel@tonic-gate 				 */
6027c478bd9Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET, he->h_addr_list,
6036392794bSMichen Chang 				    &server_port, res->nd_alist);
6047c478bd9Sstevel@tonic-gate 			} else {
6057c478bd9Sstevel@tonic-gate 				/*
6067c478bd9Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
6077c478bd9Sstevel@tonic-gate 				 * malloc's will be done, freed using
6087c478bd9Sstevel@tonic-gate 				 * netdir_free.
6097c478bd9Sstevel@tonic-gate 				 */
6107c478bd9Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET, he->h_addr_list,
6116392794bSMichen Chang 				    &server_port, res->nd_alist);
6127c478bd9Sstevel@tonic-gate 				freehostent(he);
6137c478bd9Sstevel@tonic-gate 			}
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 			_nderror = ret;
6167c478bd9Sstevel@tonic-gate 			NSS_XbyY_FREE(&ndbuf4switch);
6177c478bd9Sstevel@tonic-gate 			return (ret);
6187c478bd9Sstevel@tonic-gate 		} else {
6197c478bd9Sstevel@tonic-gate 			int ret;
6207c478bd9Sstevel@tonic-gate 			/*
6217c478bd9Sstevel@tonic-gate 			 * Convert h_addr_list into nd_addrlist.
6227c478bd9Sstevel@tonic-gate 			 * malloc's will be done, freed using netdir_free.
6237c478bd9Sstevel@tonic-gate 			 */
6247c478bd9Sstevel@tonic-gate 			ret = hent2ndaddr(AF_INET, haddrlist,
6256392794bSMichen Chang 			    &server_port, res->nd_alist);
626*d81a47b3SMilan Jurik 			return (inetdir_free(ret, inaddrs, baddrlist));
6277c478bd9Sstevel@tonic-gate 		}
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 		case NETDIR_BY6:
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 			if (servp == 0) {
6336392794bSMichen Chang 				char	*proto = (strcmp(nconf->nc_proto,
6346392794bSMichen Chang 				    NC_TCP) == 0) ? NC_TCP : NC_UDP;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 				/*
6377c478bd9Sstevel@tonic-gate 				 * We go through all this for just
6387c478bd9Sstevel@tonic-gate 				 * one port number,
6397c478bd9Sstevel@tonic-gate 				 * which is most often constant.
6407c478bd9Sstevel@tonic-gate 				 * How about linking in
6417c478bd9Sstevel@tonic-gate 				 * an indexed database of well-known
6427c478bd9Sstevel@tonic-gate 				 * ports in the name
6437c478bd9Sstevel@tonic-gate 				 * of performance ?
6447c478bd9Sstevel@tonic-gate 				 */
64561961e0fSrobinson 				ndbuf4switch = _nss_XbyY_buf_alloc(
6466392794bSMichen Chang 				    sizeof (struct servent),
6476392794bSMichen Chang 				    NSS_BUFLEN_SERVICES);
6487c478bd9Sstevel@tonic-gate 				if (ndbuf4switch == 0)
649*d81a47b3SMilan Jurik 					return (inetdir_free(ND_NOMEM, inaddrs,
650*d81a47b3SMilan Jurik 					    baddrlist));
6517c478bd9Sstevel@tonic-gate 				se = _switch_getservbyname_r(
6526392794bSMichen Chang 				    args->arg.nd_hs->h_serv,
6537c478bd9Sstevel@tonic-gate 				    proto, ndbuf4switch->result,
6547c478bd9Sstevel@tonic-gate 				    ndbuf4switch->buffer, ndbuf4switch->buflen);
6557c478bd9Sstevel@tonic-gate 				if (!se) {
6567c478bd9Sstevel@tonic-gate 					NSS_XbyY_FREE(&ndbuf4switch);
657*d81a47b3SMilan Jurik 					return (inetdir_free(ND_NOSERV, inaddrs,
658*d81a47b3SMilan Jurik 					    baddrlist));
6597c478bd9Sstevel@tonic-gate 				}
6607c478bd9Sstevel@tonic-gate 				server_port = se->s_port;
6617c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4switch);
6627c478bd9Sstevel@tonic-gate 			}
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 			if (haddrlist == 0) {
6657c478bd9Sstevel@tonic-gate 				int	h_errnop = 0;
6667c478bd9Sstevel@tonic-gate 
66761961e0fSrobinson 				ndbuf4switch = _nss_XbyY_buf_alloc(
6686392794bSMichen Chang 				    sizeof (struct hostent),
6696392794bSMichen Chang 				    NSS_BUFLEN_HOSTS);
6707c478bd9Sstevel@tonic-gate 				if (ndbuf4switch == 0) {
6717c478bd9Sstevel@tonic-gate 					_nderror = ND_NOMEM;
6727c478bd9Sstevel@tonic-gate 					return (ND_NOMEM);
6737c478bd9Sstevel@tonic-gate 				}
6747c478bd9Sstevel@tonic-gate 				he = DOOR_GETIPNODEBYNAME_R(
6757c478bd9Sstevel@tonic-gate 				    args->arg.nd_hs->h_host,
6767c478bd9Sstevel@tonic-gate 				    ndbuf4switch->result, ndbuf4switch->buffer,
6777c478bd9Sstevel@tonic-gate 				    ndbuf4switch->buflen,
6787c478bd9Sstevel@tonic-gate 				    args->arg.nss.host6.af_family,
6797c478bd9Sstevel@tonic-gate 				    args->arg.nss.host6.flags, &h_errnop);
6807c478bd9Sstevel@tonic-gate 				if (he == NULL) {
6817c478bd9Sstevel@tonic-gate 					NSS_XbyY_FREE(&ndbuf4switch);
682ba2b2c94SVitaliy Gusev 					_nderror = __herrno2netdir(h_errnop);
6837c478bd9Sstevel@tonic-gate 					return (_nderror);
6847c478bd9Sstevel@tonic-gate 				}
6857c478bd9Sstevel@tonic-gate 				/*
6867c478bd9Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
6877c478bd9Sstevel@tonic-gate 				 * malloc's will be done,
6887c478bd9Sstevel@tonic-gate 				 * freed using netdir_free.
6897c478bd9Sstevel@tonic-gate 				 */
6907c478bd9Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET6,
6916392794bSMichen Chang 				    ((struct hostent *)
6926392794bSMichen Chang 				    (ndbuf4switch->result))->h_addr_list,
6937c478bd9Sstevel@tonic-gate 				    &server_port, res->nd_alist);
6947c478bd9Sstevel@tonic-gate 				_nderror = ret;
6957c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4switch);
6967c478bd9Sstevel@tonic-gate 				return (ret);
6977c478bd9Sstevel@tonic-gate 			} else {
6987c478bd9Sstevel@tonic-gate 				int ret;
6997c478bd9Sstevel@tonic-gate 				/*
7007c478bd9Sstevel@tonic-gate 				 * Convert h_addr_list into nd_addrlist.
7017c478bd9Sstevel@tonic-gate 				 * malloc's will be done,
7027c478bd9Sstevel@tonic-gate 				 * freed using netdir_free.
7037c478bd9Sstevel@tonic-gate 				 */
7047c478bd9Sstevel@tonic-gate 				ret = hent2ndaddr(AF_INET6, haddrlist,
7056392794bSMichen Chang 				    &server_port, res->nd_alist);
706*d81a47b3SMilan Jurik 				return (inetdir_free(ret, inaddrs, baddrlist));
7077c478bd9Sstevel@tonic-gate 			}
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 		default:
7106392794bSMichen Chang 			_nderror = ND_BADARG;
7116392794bSMichen Chang 			return (ND_BADARG); /* should never happen */
7127c478bd9Sstevel@tonic-gate 	}
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	} else {
7157c478bd9Sstevel@tonic-gate 		/* haddrlist is no longer used, so clean up */
7167c478bd9Sstevel@tonic-gate 		if (inaddrs)
7177c478bd9Sstevel@tonic-gate 			free(inaddrs);
7187c478bd9Sstevel@tonic-gate 		if (baddrlist)
7197c478bd9Sstevel@tonic-gate 			free(baddrlist);
7207c478bd9Sstevel@tonic-gate 	}
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	/*
7237c478bd9Sstevel@tonic-gate 	 * 3. We come this far only if nametoaddr libs are specified for
7247c478bd9Sstevel@tonic-gate 	 *    inet transports and we are called by gethost/servbyname only.
7257c478bd9Sstevel@tonic-gate 	 */
7267c478bd9Sstevel@tonic-gate 	switch (args->op_t) {
7277c478bd9Sstevel@tonic-gate 		struct	nd_hostserv service;
7287c478bd9Sstevel@tonic-gate 		struct	nd_addrlist *addrs;
7297c478bd9Sstevel@tonic-gate 		int ret;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 		case NSS_HOST:
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 		service.h_host = (char *)args->arg.nss.host.name;
7347c478bd9Sstevel@tonic-gate 		service.h_serv = NULL;
7357c478bd9Sstevel@tonic-gate 		if ((_nderror = __classic_netdir_getbyname(nconf,
7366392794bSMichen Chang 		    &service, &addrs)) != ND_OK) {
7377c478bd9Sstevel@tonic-gate 			*(res->nss.host.herrno_p) = nd2herrno(_nderror);
7387c478bd9Sstevel@tonic-gate 			return (_nderror);
7397c478bd9Sstevel@tonic-gate 		}
7407c478bd9Sstevel@tonic-gate 		/*
7417c478bd9Sstevel@tonic-gate 		 * convert addresses back into sockaddr for gethostbyname.
7427c478bd9Sstevel@tonic-gate 		 */
7437c478bd9Sstevel@tonic-gate 		ret = ndaddr2hent(AF_INET, service.h_host, addrs,
7447c478bd9Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
7457c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.buflen);
7467c478bd9Sstevel@tonic-gate 		if (ret != ND_OK)
7477c478bd9Sstevel@tonic-gate 			*(res->nss.host.herrno_p) = nd2herrno(ret);
7487c478bd9Sstevel@tonic-gate 		netdir_free((char *)addrs, ND_ADDRLIST);
7497c478bd9Sstevel@tonic-gate 		_nderror = ret;
7507c478bd9Sstevel@tonic-gate 		return (ret);
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 		case NSS_SERV:
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 		if (args->arg.nss.serv.proto == NULL) {
7557c478bd9Sstevel@tonic-gate 			/*
7567c478bd9Sstevel@tonic-gate 			 * A similar HACK showed up in Solaris 2.3.
7577c478bd9Sstevel@tonic-gate 			 * The caller wild-carded proto -- i.e. will
7587c478bd9Sstevel@tonic-gate 			 * accept a match using tcp or udp for the port
7597c478bd9Sstevel@tonic-gate 			 * number. Since we have no hope of getting
7607c478bd9Sstevel@tonic-gate 			 * directly to a name service switch backend
7617c478bd9Sstevel@tonic-gate 			 * from here that understands this semantics,
7627c478bd9Sstevel@tonic-gate 			 * we try calling the netdir interfaces first
7637c478bd9Sstevel@tonic-gate 			 * with "tcp" and then "udp".
7647c478bd9Sstevel@tonic-gate 			 */
7657c478bd9Sstevel@tonic-gate 			args->arg.nss.serv.proto = "tcp";
7667c478bd9Sstevel@tonic-gate 			_nderror = _get_hostserv_inetnetdir_byname(nconf, args,
7677c478bd9Sstevel@tonic-gate 			    res);
7687c478bd9Sstevel@tonic-gate 			if (_nderror != ND_OK) {
7697c478bd9Sstevel@tonic-gate 				args->arg.nss.serv.proto = "udp";
7707c478bd9Sstevel@tonic-gate 				_nderror =
7717c478bd9Sstevel@tonic-gate 				    _get_hostserv_inetnetdir_byname(nconf,
7727c478bd9Sstevel@tonic-gate 				    args, res);
7737c478bd9Sstevel@tonic-gate 			}
7747c478bd9Sstevel@tonic-gate 			return (_nderror);
7757c478bd9Sstevel@tonic-gate 		}
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 		/*
7787c478bd9Sstevel@tonic-gate 		 * Third-parties should optimize their nametoaddr
7797c478bd9Sstevel@tonic-gate 		 * libraries for the HOST_SELF case.
7807c478bd9Sstevel@tonic-gate 		 */
7817c478bd9Sstevel@tonic-gate 		service.h_host = HOST_SELF;
7827c478bd9Sstevel@tonic-gate 		service.h_serv = (char *)args->arg.nss.serv.name;
7837c478bd9Sstevel@tonic-gate 		if ((_nderror = __classic_netdir_getbyname(nconf,
7846392794bSMichen Chang 		    &service, &addrs)) != ND_OK) {
7857c478bd9Sstevel@tonic-gate 			return (_nderror);
7867c478bd9Sstevel@tonic-gate 		}
7877c478bd9Sstevel@tonic-gate 		/*
7887c478bd9Sstevel@tonic-gate 		 * convert addresses back into servent for getservbyname.
7897c478bd9Sstevel@tonic-gate 		 */
7907c478bd9Sstevel@tonic-gate 		_nderror = ndaddr2srent(service.h_serv,
7917c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.proto,
79261961e0fSrobinson 		    /* LINTED pointer cast */
7937c478bd9Sstevel@tonic-gate 		    ((struct sockaddr_in *)addrs->n_addrs->buf)->sin_port,
7947c478bd9Sstevel@tonic-gate 		    res->nss.serv,
7957c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.buf, args->arg.nss.serv.buflen);
7967c478bd9Sstevel@tonic-gate 		netdir_free((char *)addrs, ND_ADDRLIST);
7977c478bd9Sstevel@tonic-gate 		return (_nderror);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 		default:
8007c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
8017c478bd9Sstevel@tonic-gate 		return (ND_BADARG); /* should never happen */
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate }
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate /*
8067c478bd9Sstevel@tonic-gate  * gethostbyaddr/servbyport always call this function; if they call
8077c478bd9Sstevel@tonic-gate  * with nametoaddr libs in nconf, we call netdir_getbyaddr
8087c478bd9Sstevel@tonic-gate  * implementation __classic_netdir_getbyaddr, otherwise nsswitch.
8097c478bd9Sstevel@tonic-gate  *
8107c478bd9Sstevel@tonic-gate  * netdir_getbyaddr calls this only if nametoaddr libs are NOT
8117c478bd9Sstevel@tonic-gate  * specified for inet transports; i.e. it's supposed to follow
8127c478bd9Sstevel@tonic-gate  * the name service switch.
8137c478bd9Sstevel@tonic-gate  */
8147c478bd9Sstevel@tonic-gate int
_get_hostserv_inetnetdir_byaddr(struct netconfig * nconf,struct nss_netdirbyaddr_in * args,union nss_netdirbyaddr_out * res)8157c478bd9Sstevel@tonic-gate _get_hostserv_inetnetdir_byaddr(struct netconfig *nconf,
8167c478bd9Sstevel@tonic-gate     struct nss_netdirbyaddr_in *args, union nss_netdirbyaddr_out *res)
8177c478bd9Sstevel@tonic-gate {
8187c478bd9Sstevel@tonic-gate 	if (nconf == 0) {
8197c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
8207c478bd9Sstevel@tonic-gate 		return (_nderror);
8217c478bd9Sstevel@tonic-gate 	}
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	/*
8247c478bd9Sstevel@tonic-gate 	 * 1. gethostbyaddr()/netdir_getbyaddr() special cases:
8257c478bd9Sstevel@tonic-gate 	 */
8267c478bd9Sstevel@tonic-gate 	switch (args->op_t) {
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 		case NSS_HOST:
8297c478bd9Sstevel@tonic-gate 		/*
8307c478bd9Sstevel@tonic-gate 		 * Worth the performance gain: assuming a lot of inet apps
8317c478bd9Sstevel@tonic-gate 		 * actively use "127.0.0.1".
8327c478bd9Sstevel@tonic-gate 		 */
83361961e0fSrobinson 		/* LINTED pointer cast */
8347c478bd9Sstevel@tonic-gate 		if (*(uint32_t *)(args->arg.nss.host.addr) ==
8356392794bSMichen Chang 		    htonl(INADDR_LOOPBACK)) {
83661961e0fSrobinson 			(void) mutex_lock(&nd_addr_lock);
8377c478bd9Sstevel@tonic-gate 			IN_SET_LOOPBACK_ADDR(&sa_con);
8387c478bd9Sstevel@tonic-gate 			_nderror = ndaddr2hent(AF_INET, LOCALHOST,
8397c478bd9Sstevel@tonic-gate 			    &nd_conaddrlist, res->nss.host.hent,
8407c478bd9Sstevel@tonic-gate 			    args->arg.nss.host.buf,
8417c478bd9Sstevel@tonic-gate 			    args->arg.nss.host.buflen);
84261961e0fSrobinson 			(void) mutex_unlock(&nd_addr_lock);
8437c478bd9Sstevel@tonic-gate 			if (_nderror != ND_OK)
8447c478bd9Sstevel@tonic-gate 				*(res->nss.host.herrno_p) =
8457c478bd9Sstevel@tonic-gate 				    nd2herrno(_nderror);
8467c478bd9Sstevel@tonic-gate 			return (_nderror);
8477c478bd9Sstevel@tonic-gate 		}
8487c478bd9Sstevel@tonic-gate 		break;
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 		case NETDIR_BY:
8517c478bd9Sstevel@tonic-gate 		case NETDIR_BY_NOSRV:
8527c478bd9Sstevel@tonic-gate 		{
8537c478bd9Sstevel@tonic-gate 			struct sockaddr_in *sin;
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 			if (args->arg.nd_nbuf == NULL) {
8567c478bd9Sstevel@tonic-gate 				_nderror = ND_BADARG;
8577c478bd9Sstevel@tonic-gate 				return (_nderror);
8587c478bd9Sstevel@tonic-gate 			}
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 			/*
8617c478bd9Sstevel@tonic-gate 			 * Validate the address which was passed
8627c478bd9Sstevel@tonic-gate 			 * as the request.
8637c478bd9Sstevel@tonic-gate 			 */
86461961e0fSrobinson 			/* LINTED pointer cast */
8657c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)args->arg.nd_nbuf->buf;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 			if ((args->arg.nd_nbuf->len !=
8686392794bSMichen Chang 			    sizeof (struct sockaddr_in)) ||
8697c478bd9Sstevel@tonic-gate 			    (sin->sin_family != AF_INET)) {
8707c478bd9Sstevel@tonic-gate 				_nderror = ND_BADARG;
8717c478bd9Sstevel@tonic-gate 				return (_nderror);
8727c478bd9Sstevel@tonic-gate 			}
8737c478bd9Sstevel@tonic-gate 		}
8747c478bd9Sstevel@tonic-gate 		break;
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 		case NETDIR_BY6:
8777c478bd9Sstevel@tonic-gate 		case NETDIR_BY_NOSRV6:
8787c478bd9Sstevel@tonic-gate 		{
8797c478bd9Sstevel@tonic-gate 			struct sockaddr_in6 *sin6;
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 			if (args->arg.nd_nbuf == NULL) {
8827c478bd9Sstevel@tonic-gate 				_nderror = ND_BADARG;
8837c478bd9Sstevel@tonic-gate 				return (_nderror);
8847c478bd9Sstevel@tonic-gate 			}
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 			/*
8877c478bd9Sstevel@tonic-gate 			 * Validate the address which was passed
8887c478bd9Sstevel@tonic-gate 			 * as the request.
8897c478bd9Sstevel@tonic-gate 			 */
89061961e0fSrobinson 			/* LINTED pointer cast */
8917c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)args->arg.nd_nbuf->buf;
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 			if ((args->arg.nd_nbuf->len !=
8946392794bSMichen Chang 			    sizeof (struct sockaddr_in6)) ||
8957c478bd9Sstevel@tonic-gate 			    (sin6->sin6_family != AF_INET6)) {
8967c478bd9Sstevel@tonic-gate 				_nderror = ND_BADARG;
8977c478bd9Sstevel@tonic-gate 				return (_nderror);
8987c478bd9Sstevel@tonic-gate 			}
8997c478bd9Sstevel@tonic-gate 		}
9007c478bd9Sstevel@tonic-gate 		break;
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	}
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	/*
9057c478bd9Sstevel@tonic-gate 	 * 2. Most common scenario. This is the way we ship /etc/netconfig.
9067c478bd9Sstevel@tonic-gate 	 *    Emphasis on improving performance in the "if" part.
9077c478bd9Sstevel@tonic-gate 	 */
9087c478bd9Sstevel@tonic-gate 	if (nconf->nc_nlookups == 0) {
9097c478bd9Sstevel@tonic-gate 		struct hostent	*he = NULL, *tmphe;
9107c478bd9Sstevel@tonic-gate 		struct servent	*se = NULL;
9117c478bd9Sstevel@tonic-gate 		nss_XbyY_buf_t	*ndbuf4host = 0;
9127c478bd9Sstevel@tonic-gate 		nss_XbyY_buf_t	*ndbuf4serv = 0;
9137c478bd9Sstevel@tonic-gate 		char	*proto =
9147c478bd9Sstevel@tonic-gate 		    (strcmp(nconf->nc_proto, NC_TCP) == 0) ? NC_TCP : NC_UDP;
9157c478bd9Sstevel@tonic-gate 		struct	sockaddr_in *sa;
9167c478bd9Sstevel@tonic-gate 		struct sockaddr_in6 *sin6;
9177c478bd9Sstevel@tonic-gate 		struct in_addr *addr4 = 0;
9187c478bd9Sstevel@tonic-gate 		struct in6_addr v4mapbuf;
9197c478bd9Sstevel@tonic-gate 		int	h_errnop;
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 	switch (args->op_t) {
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 		case NSS_HOST:
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 		he = DOOR_GETHOSTBYADDR_R(args->arg.nss.host.addr,
9267c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.len, args->arg.nss.host.type,
9277c478bd9Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
9287c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.buflen,
9297c478bd9Sstevel@tonic-gate 		    res->nss.host.herrno_p);
9307c478bd9Sstevel@tonic-gate 		if (he == 0)
9317c478bd9Sstevel@tonic-gate 			_nderror = ND_NOHOST;
9327c478bd9Sstevel@tonic-gate 		else
9337c478bd9Sstevel@tonic-gate 			_nderror = ND_OK;
9347c478bd9Sstevel@tonic-gate 		return (_nderror);
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 		case NSS_HOST6:
9387c478bd9Sstevel@tonic-gate 		he = DOOR_GETIPNODEBYADDR_R(args->arg.nss.host.addr,
9397c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.len, args->arg.nss.host.type,
9407c478bd9Sstevel@tonic-gate 		    res->nss.host.hent, args->arg.nss.host.buf,
9417c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.buflen,
9427c478bd9Sstevel@tonic-gate 		    res->nss.host.herrno_p);
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 		if (he == 0)
9457c478bd9Sstevel@tonic-gate 			return (ND_NOHOST);
9467c478bd9Sstevel@tonic-gate 		return (ND_OK);
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 		case NSS_SERV:
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 		se = _switch_getservbyport_r(args->arg.nss.serv.port,
9527c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.proto,
9537c478bd9Sstevel@tonic-gate 		    res->nss.serv, args->arg.nss.serv.buf,
9547c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.buflen);
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 		if (se == 0)
9577c478bd9Sstevel@tonic-gate 			_nderror = ND_NOSERV;
9587c478bd9Sstevel@tonic-gate 		else
9597c478bd9Sstevel@tonic-gate 			_nderror = ND_OK;
9607c478bd9Sstevel@tonic-gate 		return (_nderror);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 		case NETDIR_BY:
9637c478bd9Sstevel@tonic-gate 		case NETDIR_BY_NOSRV:
9647c478bd9Sstevel@tonic-gate 
96561961e0fSrobinson 		ndbuf4serv = _nss_XbyY_buf_alloc(sizeof (struct servent),
9666392794bSMichen Chang 		    NSS_BUFLEN_SERVICES);
9677c478bd9Sstevel@tonic-gate 		if (ndbuf4serv == 0) {
9687c478bd9Sstevel@tonic-gate 			_nderror = ND_NOMEM;
9697c478bd9Sstevel@tonic-gate 			return (_nderror);
9707c478bd9Sstevel@tonic-gate 		}
97161961e0fSrobinson 		/* LINTED pointer cast */
9727c478bd9Sstevel@tonic-gate 		sa = (struct sockaddr_in *)(args->arg.nd_nbuf->buf);
9737c478bd9Sstevel@tonic-gate 		addr4 = (struct in_addr *)&(sa->sin_addr);
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 		/*
9767c478bd9Sstevel@tonic-gate 		 * if NETDIR_BY_NOSRV or port == 0 skip the service
9777c478bd9Sstevel@tonic-gate 		 * lookup.
9787c478bd9Sstevel@tonic-gate 		 */
9797c478bd9Sstevel@tonic-gate 		if (args->op_t != NETDIR_BY_NOSRV && sa->sin_port != 0) {
9807c478bd9Sstevel@tonic-gate 			se = _switch_getservbyport_r(sa->sin_port, proto,
9817c478bd9Sstevel@tonic-gate 			    ndbuf4serv->result, ndbuf4serv->buffer,
9826392794bSMichen Chang 			    ndbuf4serv->buflen);
9837c478bd9Sstevel@tonic-gate 			if (!se) {
9847c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4serv);
9857c478bd9Sstevel@tonic-gate 				/*
9867c478bd9Sstevel@tonic-gate 				 * We can live with this - i.e. the address
9877c478bd9Sstevel@tonic-gate 				 * does not
9887c478bd9Sstevel@tonic-gate 				 * belong to a well known service. The caller
9897c478bd9Sstevel@tonic-gate 				 * traditionally accepts a stringified port
9907c478bd9Sstevel@tonic-gate 				 * number
9917c478bd9Sstevel@tonic-gate 				 * as the service name. The state of se is used
9927c478bd9Sstevel@tonic-gate 				 * ahead to indicate the same.
9937c478bd9Sstevel@tonic-gate 				 * However, we do not tolerate this nonsense
9947c478bd9Sstevel@tonic-gate 				 * when we cannot get a host name. See below.
9957c478bd9Sstevel@tonic-gate 				 */
9967c478bd9Sstevel@tonic-gate 			}
9977c478bd9Sstevel@tonic-gate 		}
9987c478bd9Sstevel@tonic-gate 
99961961e0fSrobinson 		ndbuf4host = _nss_XbyY_buf_alloc(sizeof (struct hostent),
10006392794bSMichen Chang 		    NSS_BUFLEN_HOSTS);
10017c478bd9Sstevel@tonic-gate 		if (ndbuf4host == 0) {
10027c478bd9Sstevel@tonic-gate 			if (ndbuf4serv)
10037c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4serv);
10047c478bd9Sstevel@tonic-gate 			_nderror = ND_NOMEM;
10057c478bd9Sstevel@tonic-gate 			return (_nderror);
10067c478bd9Sstevel@tonic-gate 		}
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 		/*
10097c478bd9Sstevel@tonic-gate 		 * Since we're going to search the ipnodes (v6) path first,
10107c478bd9Sstevel@tonic-gate 		 * we need to treat the address as a v4mapped address.
10117c478bd9Sstevel@tonic-gate 		 */
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 		IN6_INADDR_TO_V4MAPPED(addr4, &v4mapbuf);
10147c478bd9Sstevel@tonic-gate 		if ((tmphe = DOOR_GETIPNODEBYADDR_R((char *)&v4mapbuf,
10157c478bd9Sstevel@tonic-gate 		    16, AF_INET6, ndbuf4host->result,
10166392794bSMichen Chang 		    ndbuf4host->buffer,
10176392794bSMichen Chang 		    ndbuf4host->buflen, &h_errnop)) != NULL)
10187c478bd9Sstevel@tonic-gate 			he = __mappedtov4(tmphe, &h_errnop);
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 		if (!he) {
10217c478bd9Sstevel@tonic-gate 			/* Failover case, try hosts db for v4 address */
10227c478bd9Sstevel@tonic-gate 			he = DOOR_GETHOSTBYADDR_R((char *)
10236392794bSMichen Chang 			    &(sa->sin_addr.s_addr), 4,
10246392794bSMichen Chang 			    sa->sin_family, ndbuf4host->result,
10256392794bSMichen Chang 			    ndbuf4host->buffer, ndbuf4host->buflen,
10266392794bSMichen Chang 			    &h_errnop);
10277c478bd9Sstevel@tonic-gate 			if (!he) {
10287c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4host);
10297c478bd9Sstevel@tonic-gate 				if (ndbuf4serv)
10307c478bd9Sstevel@tonic-gate 					NSS_XbyY_FREE(&ndbuf4serv);
10317c478bd9Sstevel@tonic-gate 				_nderror = __herrno2netdir(h_errnop);
10327c478bd9Sstevel@tonic-gate 				return (_nderror);
10337c478bd9Sstevel@tonic-gate 			}
10347c478bd9Sstevel@tonic-gate 			/*
10357c478bd9Sstevel@tonic-gate 			 * Convert host names and service names into hostserv
10367c478bd9Sstevel@tonic-gate 			 * pairs. malloc's will be done, freed using
10377c478bd9Sstevel@tonic-gate 			 * netdir_free.
10387c478bd9Sstevel@tonic-gate 			 */
10397c478bd9Sstevel@tonic-gate 			h_errnop = hsents2ndhostservs(he, se,
10407c478bd9Sstevel@tonic-gate 			    sa->sin_port, res->nd_hslist);
10417c478bd9Sstevel@tonic-gate 		} else {
10427c478bd9Sstevel@tonic-gate 			/*
10437c478bd9Sstevel@tonic-gate 			 * Convert host names and service names into hostserv
10447c478bd9Sstevel@tonic-gate 			 * pairs. malloc's will be done, freed using
10457c478bd9Sstevel@tonic-gate 			 * netdir_free.
10467c478bd9Sstevel@tonic-gate 			 */
10477c478bd9Sstevel@tonic-gate 			h_errnop = hsents2ndhostservs(he, se,
10487c478bd9Sstevel@tonic-gate 			    sa->sin_port, res->nd_hslist);
10497c478bd9Sstevel@tonic-gate 			freehostent(he);
10507c478bd9Sstevel@tonic-gate 		}
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 		NSS_XbyY_FREE(&ndbuf4host);
10537c478bd9Sstevel@tonic-gate 		if (ndbuf4serv)
10546392794bSMichen Chang 			NSS_XbyY_FREE(&ndbuf4serv);
10557c478bd9Sstevel@tonic-gate 		_nderror = __herrno2netdir(h_errnop);
10567c478bd9Sstevel@tonic-gate 		return (_nderror);
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 		case NETDIR_BY6:
10597c478bd9Sstevel@tonic-gate 		case NETDIR_BY_NOSRV6:
10607c478bd9Sstevel@tonic-gate 
106161961e0fSrobinson 		ndbuf4serv = _nss_XbyY_buf_alloc(sizeof (struct servent),
10626392794bSMichen Chang 		    NSS_BUFLEN_SERVICES);
10637c478bd9Sstevel@tonic-gate 		if (ndbuf4serv == 0) {
10647c478bd9Sstevel@tonic-gate 			_nderror = ND_NOMEM;
10657c478bd9Sstevel@tonic-gate 			return (ND_NOMEM);
10667c478bd9Sstevel@tonic-gate 		}
106761961e0fSrobinson 		/* LINTED pointer cast */
10687c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)(args->arg.nd_nbuf->buf);
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 		/*
10717c478bd9Sstevel@tonic-gate 		 * if NETDIR_BY_NOSRV6 or port == 0 skip the service
10727c478bd9Sstevel@tonic-gate 		 * lookup.
10737c478bd9Sstevel@tonic-gate 		 */
10747c478bd9Sstevel@tonic-gate 		if (args->op_t != NETDIR_BY_NOSRV6 && sin6->sin6_port == 0) {
10757c478bd9Sstevel@tonic-gate 			se = _switch_getservbyport_r(sin6->sin6_port, proto,
10767c478bd9Sstevel@tonic-gate 			    ndbuf4serv->result, ndbuf4serv->buffer,
10776392794bSMichen Chang 			    ndbuf4serv->buflen);
10787c478bd9Sstevel@tonic-gate 			if (!se) {
10797c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4serv);
10807c478bd9Sstevel@tonic-gate 				/*
10817c478bd9Sstevel@tonic-gate 				 * We can live with this - i.e. the address does
10827c478bd9Sstevel@tonic-gate 				 * not * belong to a well known service. The
10837c478bd9Sstevel@tonic-gate 				 * caller traditionally accepts a stringified
10847c478bd9Sstevel@tonic-gate 				 * port number
10857c478bd9Sstevel@tonic-gate 				 * as the service name. The state of se is used
10867c478bd9Sstevel@tonic-gate 				 * ahead to indicate the same.
10877c478bd9Sstevel@tonic-gate 				 * However, we do not tolerate this nonsense
10887c478bd9Sstevel@tonic-gate 				 * when we cannot get a host name. See below.
10897c478bd9Sstevel@tonic-gate 				 */
10907c478bd9Sstevel@tonic-gate 			}
10917c478bd9Sstevel@tonic-gate 		}
10927c478bd9Sstevel@tonic-gate 
109361961e0fSrobinson 		ndbuf4host = _nss_XbyY_buf_alloc(sizeof (struct hostent),
10946392794bSMichen Chang 		    NSS_BUFLEN_HOSTS);
10957c478bd9Sstevel@tonic-gate 		if (ndbuf4host == 0) {
10967c478bd9Sstevel@tonic-gate 			if (ndbuf4serv)
10977c478bd9Sstevel@tonic-gate 				NSS_XbyY_FREE(&ndbuf4serv);
10987c478bd9Sstevel@tonic-gate 			_nderror = ND_NOMEM;
10997c478bd9Sstevel@tonic-gate 			return (_nderror);
11007c478bd9Sstevel@tonic-gate 		}
11017c478bd9Sstevel@tonic-gate 		he = DOOR_GETIPNODEBYADDR_R((char *)&(sin6->sin6_addr),
11027c478bd9Sstevel@tonic-gate 		    16, sin6->sin6_family, ndbuf4host->result,
11036392794bSMichen Chang 		    ndbuf4host->buffer,
11046392794bSMichen Chang 		    ndbuf4host->buflen, &h_errnop);
11057c478bd9Sstevel@tonic-gate 		if (!he) {
11067c478bd9Sstevel@tonic-gate 			NSS_XbyY_FREE(&ndbuf4host);
11077c478bd9Sstevel@tonic-gate 			if (ndbuf4serv)
11086392794bSMichen Chang 				NSS_XbyY_FREE(&ndbuf4serv);
11097c478bd9Sstevel@tonic-gate 			_nderror = __herrno2netdir(h_errnop);
11107c478bd9Sstevel@tonic-gate 			return (_nderror);
11117c478bd9Sstevel@tonic-gate 		}
11127c478bd9Sstevel@tonic-gate 		/*
11137c478bd9Sstevel@tonic-gate 		 * Convert host names and service names into hostserv
11147c478bd9Sstevel@tonic-gate 		 * pairs. malloc's will be done, freed using netdir_free.
11157c478bd9Sstevel@tonic-gate 		 */
11167c478bd9Sstevel@tonic-gate 		h_errnop = hsents2ndhostservs(he, se,
11177c478bd9Sstevel@tonic-gate 		    sin6->sin6_port, res->nd_hslist);
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 		NSS_XbyY_FREE(&ndbuf4host);
11207c478bd9Sstevel@tonic-gate 		if (ndbuf4serv)
11216392794bSMichen Chang 			NSS_XbyY_FREE(&ndbuf4serv);
11227c478bd9Sstevel@tonic-gate 		_nderror = __herrno2netdir(h_errnop);
11237c478bd9Sstevel@tonic-gate 		return (_nderror);
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 		default:
11267c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
11277c478bd9Sstevel@tonic-gate 		return (_nderror); /* should never happen */
11287c478bd9Sstevel@tonic-gate 	}
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	}
11317c478bd9Sstevel@tonic-gate 	/*
11327c478bd9Sstevel@tonic-gate 	 * 3. We come this far only if nametoaddr libs are specified for
11337c478bd9Sstevel@tonic-gate 	 *    inet transports and we are called by gethost/servbyname only.
11347c478bd9Sstevel@tonic-gate 	 */
11357c478bd9Sstevel@tonic-gate 	switch (args->op_t) {
11367c478bd9Sstevel@tonic-gate 		struct	netbuf nbuf;
11377c478bd9Sstevel@tonic-gate 		struct	nd_hostservlist *addrs;
11387c478bd9Sstevel@tonic-gate 		struct	sockaddr_in sa;
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 		case NSS_HOST:
11417c478bd9Sstevel@tonic-gate 
114261961e0fSrobinson 		/* LINTED pointer cast */
11437c478bd9Sstevel@tonic-gate 		sa.sin_addr.s_addr = *(uint32_t *)args->arg.nss.host.addr;
11447c478bd9Sstevel@tonic-gate 		sa.sin_family = AF_INET;
11457c478bd9Sstevel@tonic-gate 		/* Hopefully, third-parties get this optimization */
11467c478bd9Sstevel@tonic-gate 		sa.sin_port = 0;
11477c478bd9Sstevel@tonic-gate 		nbuf.buf = (char *)&sa;
11487c478bd9Sstevel@tonic-gate 		nbuf.len = nbuf.maxlen = sizeof (sa);
11497c478bd9Sstevel@tonic-gate 		if ((_nderror = __classic_netdir_getbyaddr(nconf,
11506392794bSMichen Chang 		    &addrs, &nbuf)) != 0) {
11517c478bd9Sstevel@tonic-gate 			*(res->nss.host.herrno_p) = nd2herrno(_nderror);
11527c478bd9Sstevel@tonic-gate 			return (_nderror);
11537c478bd9Sstevel@tonic-gate 		}
11547c478bd9Sstevel@tonic-gate 		/*
11557c478bd9Sstevel@tonic-gate 		 * convert the host-serv pairs into h_aliases and hent.
11567c478bd9Sstevel@tonic-gate 		 */
11577c478bd9Sstevel@tonic-gate 		_nderror = ndhostserv2hent(&nbuf, addrs, res->nss.host.hent,
11587c478bd9Sstevel@tonic-gate 		    args->arg.nss.host.buf, args->arg.nss.host.buflen);
11597c478bd9Sstevel@tonic-gate 		if (_nderror != ND_OK)
11607c478bd9Sstevel@tonic-gate 			*(res->nss.host.herrno_p) = nd2herrno(_nderror);
11617c478bd9Sstevel@tonic-gate 		netdir_free((char *)addrs, ND_HOSTSERVLIST);
11627c478bd9Sstevel@tonic-gate 		return (_nderror);
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 		case NSS_SERV:
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 		if (args->arg.nss.serv.proto == NULL) {
11677c478bd9Sstevel@tonic-gate 			/*
11687c478bd9Sstevel@tonic-gate 			 * A similar HACK showed up in Solaris 2.3.
11697c478bd9Sstevel@tonic-gate 			 * The caller wild-carded proto -- i.e. will
11707c478bd9Sstevel@tonic-gate 			 * accept a match on tcp or udp for the port
11717c478bd9Sstevel@tonic-gate 			 * number. Since we have no hope of getting
11727c478bd9Sstevel@tonic-gate 			 * directly to a name service switch backend
11737c478bd9Sstevel@tonic-gate 			 * from here that understands this semantics,
11747c478bd9Sstevel@tonic-gate 			 * we try calling the netdir interfaces first
11757c478bd9Sstevel@tonic-gate 			 * with "tcp" and then "udp".
11767c478bd9Sstevel@tonic-gate 			 */
11777c478bd9Sstevel@tonic-gate 			args->arg.nss.serv.proto = "tcp";
11787c478bd9Sstevel@tonic-gate 			_nderror = _get_hostserv_inetnetdir_byaddr(nconf, args,
11797c478bd9Sstevel@tonic-gate 			    res);
11807c478bd9Sstevel@tonic-gate 			if (_nderror != ND_OK) {
11817c478bd9Sstevel@tonic-gate 				args->arg.nss.serv.proto = "udp";
11827c478bd9Sstevel@tonic-gate 				_nderror =
11837c478bd9Sstevel@tonic-gate 				    _get_hostserv_inetnetdir_byaddr(nconf,
11846392794bSMichen Chang 				    args, res);
11857c478bd9Sstevel@tonic-gate 			}
11867c478bd9Sstevel@tonic-gate 			return (_nderror);
11877c478bd9Sstevel@tonic-gate 		}
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 		/*
11907c478bd9Sstevel@tonic-gate 		 * Third-party nametoaddr_libs should be optimized for
11917c478bd9Sstevel@tonic-gate 		 * this case. It also gives a special semantics twist to
11927c478bd9Sstevel@tonic-gate 		 * netdir_getbyaddr. Only for the INADDR_ANY case, it gives
11937c478bd9Sstevel@tonic-gate 		 * higher priority to service lookups (over host lookups).
11947c478bd9Sstevel@tonic-gate 		 * If service lookup fails, the backend returns ND_NOSERV to
11957c478bd9Sstevel@tonic-gate 		 * facilitate lookup in the "next" naming service.
11967c478bd9Sstevel@tonic-gate 		 * BugId: 1075403.
11977c478bd9Sstevel@tonic-gate 		 */
11987c478bd9Sstevel@tonic-gate 		sa.sin_addr.s_addr = INADDR_ANY;
11997c478bd9Sstevel@tonic-gate 		sa.sin_family = AF_INET;
12007c478bd9Sstevel@tonic-gate 		sa.sin_port = (ushort_t)args->arg.nss.serv.port;
12017c478bd9Sstevel@tonic-gate 		sa.sin_zero[0] = '\0';
12027c478bd9Sstevel@tonic-gate 		nbuf.buf = (char *)&sa;
12037c478bd9Sstevel@tonic-gate 		nbuf.len = nbuf.maxlen = sizeof (sa);
12047c478bd9Sstevel@tonic-gate 		if ((_nderror = __classic_netdir_getbyaddr(nconf,
12056392794bSMichen Chang 		    &addrs, &nbuf)) != ND_OK) {
12067c478bd9Sstevel@tonic-gate 			return (_nderror);
12077c478bd9Sstevel@tonic-gate 		}
12087c478bd9Sstevel@tonic-gate 		/*
12097c478bd9Sstevel@tonic-gate 		 * convert the host-serv pairs into s_aliases and servent.
12107c478bd9Sstevel@tonic-gate 		 */
12117c478bd9Sstevel@tonic-gate 		_nderror = ndhostserv2srent(args->arg.nss.serv.port,
12127c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.proto, addrs, res->nss.serv,
12137c478bd9Sstevel@tonic-gate 		    args->arg.nss.serv.buf, args->arg.nss.serv.buflen);
12147c478bd9Sstevel@tonic-gate 		netdir_free((char *)addrs, ND_HOSTSERVLIST);
12157c478bd9Sstevel@tonic-gate 		return (_nderror);
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 		default:
12187c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
12197c478bd9Sstevel@tonic-gate 		return (_nderror); /* should never happen */
12207c478bd9Sstevel@tonic-gate 	}
12217c478bd9Sstevel@tonic-gate }
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate /*
12247c478bd9Sstevel@tonic-gate  * Part II: Name Service Switch interfacing routines.
12257c478bd9Sstevel@tonic-gate  */
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_hosts);
12287c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_ipnodes);
12297c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_services);
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate /*
12337c478bd9Sstevel@tonic-gate  * There is a copy of __nss2herrno() in nsswitch/files/gethostent.c.
12347c478bd9Sstevel@tonic-gate  * It is there because /etc/lib/nss_files.so.1 cannot call
12357c478bd9Sstevel@tonic-gate  * routines in libnsl.  Care should be taken to keep the two copies
12366392794bSMichen Chang  * in sync (except that case NSS_NISSERVDNS_TRYAGAIN is not needed in
12376392794bSMichen Chang  * nsswitch/files).
12387c478bd9Sstevel@tonic-gate  */
12397c478bd9Sstevel@tonic-gate int
__nss2herrno(nss_status_t nsstat)12407c478bd9Sstevel@tonic-gate __nss2herrno(nss_status_t nsstat)
12417c478bd9Sstevel@tonic-gate {
12427c478bd9Sstevel@tonic-gate 	switch (nsstat) {
12437c478bd9Sstevel@tonic-gate 	case NSS_SUCCESS:
12447c478bd9Sstevel@tonic-gate 		/* no macro-defined success code for h_errno */
12457c478bd9Sstevel@tonic-gate 		return (0);
12467c478bd9Sstevel@tonic-gate 	case NSS_NOTFOUND:
12477c478bd9Sstevel@tonic-gate 		return (HOST_NOT_FOUND);
12487c478bd9Sstevel@tonic-gate 	case NSS_TRYAGAIN:
12497c478bd9Sstevel@tonic-gate 		return (TRY_AGAIN);
12507c478bd9Sstevel@tonic-gate 	case NSS_UNAVAIL:
12517c478bd9Sstevel@tonic-gate 		return (NO_RECOVERY);
12526392794bSMichen Chang 	case NSS_NISSERVDNS_TRYAGAIN:
12536392794bSMichen Chang 		return (TRY_AGAIN);
12547c478bd9Sstevel@tonic-gate 	}
12556392794bSMichen Chang 	/* anything else */
12566392794bSMichen Chang 	return (NO_RECOVERY);
12577c478bd9Sstevel@tonic-gate }
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate nss_status_t
_herrno2nss(int h_errno)12607c478bd9Sstevel@tonic-gate _herrno2nss(int h_errno)
12617c478bd9Sstevel@tonic-gate {
12627c478bd9Sstevel@tonic-gate 	switch (h_errno) {
12637c478bd9Sstevel@tonic-gate 	case 0:
12647c478bd9Sstevel@tonic-gate 		return (NSS_SUCCESS);
12657c478bd9Sstevel@tonic-gate 	case TRY_AGAIN:
12667c478bd9Sstevel@tonic-gate 		return (NSS_TRYAGAIN);
12677c478bd9Sstevel@tonic-gate 	case NO_RECOVERY:
12687c478bd9Sstevel@tonic-gate 	case NETDB_INTERNAL:
12697c478bd9Sstevel@tonic-gate 		return (NSS_UNAVAIL);
12707c478bd9Sstevel@tonic-gate 	case HOST_NOT_FOUND:
12717c478bd9Sstevel@tonic-gate 	case NO_DATA:
12727c478bd9Sstevel@tonic-gate 	default:
12737c478bd9Sstevel@tonic-gate 		return (NSS_NOTFOUND);
12747c478bd9Sstevel@tonic-gate 	}
12757c478bd9Sstevel@tonic-gate }
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate static int
__herrno2netdir(int h_errnop)12787c478bd9Sstevel@tonic-gate __herrno2netdir(int h_errnop)
12797c478bd9Sstevel@tonic-gate {
12807c478bd9Sstevel@tonic-gate 	switch (h_errnop) {
12817c478bd9Sstevel@tonic-gate 		case 0:
12827c478bd9Sstevel@tonic-gate 			return (ND_OK);
12837c478bd9Sstevel@tonic-gate 		case HOST_NOT_FOUND:
12847c478bd9Sstevel@tonic-gate 			return (ND_NOHOST);
12857c478bd9Sstevel@tonic-gate 		case TRY_AGAIN:
12867c478bd9Sstevel@tonic-gate 			return (ND_TRY_AGAIN);
12877c478bd9Sstevel@tonic-gate 		case NO_RECOVERY:
12887c478bd9Sstevel@tonic-gate 		case NETDB_INTERNAL:
12897c478bd9Sstevel@tonic-gate 			return (ND_NO_RECOVERY);
12907c478bd9Sstevel@tonic-gate 		case NO_DATA:
12917c478bd9Sstevel@tonic-gate 			return (ND_NO_DATA);
12927c478bd9Sstevel@tonic-gate 		default:
12937c478bd9Sstevel@tonic-gate 			return (ND_NOHOST);
12947c478bd9Sstevel@tonic-gate 	}
12957c478bd9Sstevel@tonic-gate }
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate /*
12987c478bd9Sstevel@tonic-gate  * The _switch_getXXbyYY_r() routines should be static.  They used to
12997c478bd9Sstevel@tonic-gate  * be exported in SunOS 5.3, and in fact publicised as work-around
13007c478bd9Sstevel@tonic-gate  * interfaces for getting CNAME/aliases, and therefore, we preserve
13017c478bd9Sstevel@tonic-gate  * their signatures here. Just in case.
13027c478bd9Sstevel@tonic-gate  */
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate struct hostent *
_switch_gethostbyname_r(const char * name,struct hostent * result,char * buffer,int buflen,int * h_errnop)13057c478bd9Sstevel@tonic-gate _switch_gethostbyname_r(const char *name, struct hostent *result, char *buffer,
13067c478bd9Sstevel@tonic-gate     int buflen, int *h_errnop)
13077c478bd9Sstevel@tonic-gate {
13087c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
13097c478bd9Sstevel@tonic-gate 	nss_status_t	res;
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent);
13127c478bd9Sstevel@tonic-gate 	arg.key.name	= name;
13137c478bd9Sstevel@tonic-gate 	arg.stayopen	= 0;
13147c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root_hosts, _nss_initf_hosts,
13157c478bd9Sstevel@tonic-gate 	    NSS_DBOP_HOSTS_BYNAME, &arg);
13167c478bd9Sstevel@tonic-gate 	arg.status = res;
1317ba2b2c94SVitaliy Gusev 	if (res != NSS_SUCCESS)
1318ba2b2c94SVitaliy Gusev 		*h_errnop = arg.h_errno ? arg.h_errno : __nss2herrno(res);
13197c478bd9Sstevel@tonic-gate 	if (arg.returnval != NULL)
13207c478bd9Sstevel@tonic-gate 		order_haddrlist_af(result->h_addrtype, result->h_addr_list);
13217c478bd9Sstevel@tonic-gate 	return ((struct hostent *)NSS_XbyY_FINI(&arg));
13227c478bd9Sstevel@tonic-gate }
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@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)13257c478bd9Sstevel@tonic-gate _switch_getipnodebyname_r(const char *name, struct hostent *result,
13267c478bd9Sstevel@tonic-gate     char *buffer, int buflen, int af_family, int flags, int *h_errnop)
13277c478bd9Sstevel@tonic-gate {
13287c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
13297c478bd9Sstevel@tonic-gate 	nss_status_t	res;
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6);
13327c478bd9Sstevel@tonic-gate 	arg.key.ipnode.name	= name;
13337c478bd9Sstevel@tonic-gate 	arg.key.ipnode.af_family = af_family;
13347c478bd9Sstevel@tonic-gate 	arg.key.ipnode.flags = flags;
13357c478bd9Sstevel@tonic-gate 	arg.stayopen	= 0;
13367c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes,
13377c478bd9Sstevel@tonic-gate 	    NSS_DBOP_IPNODES_BYNAME, &arg);
13387c478bd9Sstevel@tonic-gate 	arg.status = res;
1339ba2b2c94SVitaliy Gusev 	if (res != NSS_SUCCESS)
1340ba2b2c94SVitaliy Gusev 		*h_errnop = arg.h_errno ? arg.h_errno : __nss2herrno(res);
13417c478bd9Sstevel@tonic-gate 	if (arg.returnval != NULL)
13427c478bd9Sstevel@tonic-gate 		order_haddrlist_af(result->h_addrtype, result->h_addr_list);
13437c478bd9Sstevel@tonic-gate 	return ((struct hostent *)NSS_XbyY_FINI(&arg));
13447c478bd9Sstevel@tonic-gate }
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate struct hostent *
_switch_gethostbyaddr_r(const char * addr,int len,int type,struct hostent * result,char * buffer,int buflen,int * h_errnop)13477c478bd9Sstevel@tonic-gate _switch_gethostbyaddr_r(const char *addr, int len, int type,
13487c478bd9Sstevel@tonic-gate     struct hostent *result, char *buffer, int buflen, int *h_errnop)
13497c478bd9Sstevel@tonic-gate {
13507c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
13517c478bd9Sstevel@tonic-gate 	nss_status_t	res;
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent);
13547c478bd9Sstevel@tonic-gate 	arg.key.hostaddr.addr	= addr;
13557c478bd9Sstevel@tonic-gate 	arg.key.hostaddr.len	= len;
13567c478bd9Sstevel@tonic-gate 	arg.key.hostaddr.type	= type;
13577c478bd9Sstevel@tonic-gate 	arg.stayopen		= 0;
13587c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root_hosts, _nss_initf_hosts,
13597c478bd9Sstevel@tonic-gate 	    NSS_DBOP_HOSTS_BYADDR, &arg);
13607c478bd9Sstevel@tonic-gate 	arg.status = res;
1361ba2b2c94SVitaliy Gusev 	if (res != NSS_SUCCESS)
1362ba2b2c94SVitaliy Gusev 		*h_errnop = arg.h_errno ? arg.h_errno : __nss2herrno(res);
13637c478bd9Sstevel@tonic-gate 	return (struct hostent *)NSS_XbyY_FINI(&arg);
13647c478bd9Sstevel@tonic-gate }
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate struct hostent *
_switch_getipnodebyaddr_r(const char * addr,int len,int type,struct hostent * result,char * buffer,int buflen,int * h_errnop)13677c478bd9Sstevel@tonic-gate _switch_getipnodebyaddr_r(const char *addr, int len, int type,
13687c478bd9Sstevel@tonic-gate     struct hostent *result, char *buffer, int buflen, int *h_errnop)
13697c478bd9Sstevel@tonic-gate {
13707c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
13717c478bd9Sstevel@tonic-gate 	nss_status_t	res;
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent6);
13747c478bd9Sstevel@tonic-gate 	arg.key.hostaddr.addr	= addr;
13757c478bd9Sstevel@tonic-gate 	arg.key.hostaddr.len	= len;
13767c478bd9Sstevel@tonic-gate 	arg.key.hostaddr.type	= type;
13777c478bd9Sstevel@tonic-gate 	arg.stayopen		= 0;
13787c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root_ipnodes, _nss_initf_ipnodes,
13797c478bd9Sstevel@tonic-gate 	    NSS_DBOP_IPNODES_BYADDR, &arg);
13807c478bd9Sstevel@tonic-gate 	arg.status = res;
1381ba2b2c94SVitaliy Gusev 	if (res != NSS_SUCCESS)
1382ba2b2c94SVitaliy Gusev 		*h_errnop = arg.h_errno ? arg.h_errno : __nss2herrno(res);
13837c478bd9Sstevel@tonic-gate 	return (struct hostent *)NSS_XbyY_FINI(&arg);
13847c478bd9Sstevel@tonic-gate }
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate static void
_nss_initf_services(nss_db_params_t * p)13877c478bd9Sstevel@tonic-gate _nss_initf_services(nss_db_params_t *p)
13887c478bd9Sstevel@tonic-gate {
13897c478bd9Sstevel@tonic-gate 	p->name	= NSS_DBNAM_SERVICES;
13907c478bd9Sstevel@tonic-gate 	p->default_config = NSS_DEFCONF_SERVICES;
13917c478bd9Sstevel@tonic-gate }
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate struct servent *
_switch_getservbyname_r(const char * name,const char * proto,struct servent * result,char * buffer,int buflen)13947c478bd9Sstevel@tonic-gate _switch_getservbyname_r(const char *name, const char *proto,
13957c478bd9Sstevel@tonic-gate     struct servent *result, char *buffer, int buflen)
13967c478bd9Sstevel@tonic-gate {
13977c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
13987c478bd9Sstevel@tonic-gate 	nss_status_t	res;
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent);
14017c478bd9Sstevel@tonic-gate 	arg.key.serv.serv.name	= name;
14027c478bd9Sstevel@tonic-gate 	arg.key.serv.proto	= proto;
14037c478bd9Sstevel@tonic-gate 	arg.stayopen		= 0;
14047c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root_services, _nss_initf_services,
14057c478bd9Sstevel@tonic-gate 	    NSS_DBOP_SERVICES_BYNAME, &arg);
14067c478bd9Sstevel@tonic-gate 	arg.status = res;
14077c478bd9Sstevel@tonic-gate 	return ((struct servent *)NSS_XbyY_FINI(&arg));
14087c478bd9Sstevel@tonic-gate }
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate struct servent *
_switch_getservbyport_r(int port,const char * proto,struct servent * result,char * buffer,int buflen)14117c478bd9Sstevel@tonic-gate _switch_getservbyport_r(int port, const char *proto, struct servent *result,
14127c478bd9Sstevel@tonic-gate     char *buffer, int buflen)
14137c478bd9Sstevel@tonic-gate {
14147c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
14157c478bd9Sstevel@tonic-gate 	nss_status_t	res;
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent);
14187c478bd9Sstevel@tonic-gate 	arg.key.serv.serv.port	= port;
14197c478bd9Sstevel@tonic-gate 	arg.key.serv.proto	= proto;
14207c478bd9Sstevel@tonic-gate 	arg.stayopen		= 0;
14217c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root_services, _nss_initf_services,
14227c478bd9Sstevel@tonic-gate 	    NSS_DBOP_SERVICES_BYPORT, &arg);
14237c478bd9Sstevel@tonic-gate 	arg.status = res;
14247c478bd9Sstevel@tonic-gate 	return ((struct servent *)NSS_XbyY_FINI(&arg));
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate /*
14297c478bd9Sstevel@tonic-gate  * Return values: 0 = success, 1 = parse error, 2 = erange ...
14307c478bd9Sstevel@tonic-gate  * The structure pointer passed in is a structure in the caller's space
14317c478bd9Sstevel@tonic-gate  * wherein the field pointers would be set to areas in the buffer if
14327c478bd9Sstevel@tonic-gate  * need be. instring and buffer should be separate areas.
14337c478bd9Sstevel@tonic-gate  *
14347c478bd9Sstevel@tonic-gate  * Defined here because we need it and we (libnsl) cannot have a dependency
14357c478bd9Sstevel@tonic-gate  * on libsocket (however, libsocket always depends on libnsl).
14367c478bd9Sstevel@tonic-gate  */
14377c478bd9Sstevel@tonic-gate int
str2servent(const char * instr,int lenstr,void * ent,char * buffer,int buflen)14387c478bd9Sstevel@tonic-gate str2servent(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
14397c478bd9Sstevel@tonic-gate {
14407c478bd9Sstevel@tonic-gate 	struct servent	*serv	= (struct servent *)ent;
14417c478bd9Sstevel@tonic-gate 	const char	*p, *fieldstart, *limit, *namestart;
14427c478bd9Sstevel@tonic-gate 	ssize_t		fieldlen, namelen = 0;
14437c478bd9Sstevel@tonic-gate 	char		numbuf[12];
14447c478bd9Sstevel@tonic-gate 	char		*numend;
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 	if ((instr >= buffer && (buffer + buflen) > instr) ||
14477c478bd9Sstevel@tonic-gate 	    (buffer >= instr && (instr + lenstr) > buffer)) {
14487c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
14497c478bd9Sstevel@tonic-gate 	}
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	p = instr;
14527c478bd9Sstevel@tonic-gate 	limit = p + lenstr;
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	while (p < limit && isspace(*p)) {
14557c478bd9Sstevel@tonic-gate 		p++;
14567c478bd9Sstevel@tonic-gate 	}
14577c478bd9Sstevel@tonic-gate 	namestart = p;
14587c478bd9Sstevel@tonic-gate 	while (p < limit && !isspace(*p)) {
14597c478bd9Sstevel@tonic-gate 		p++;		/* Skip over the canonical name */
14607c478bd9Sstevel@tonic-gate 	}
14617c478bd9Sstevel@tonic-gate 	namelen = p - namestart;
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	if (buflen <= namelen) { /* not enough buffer */
14647c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
14657c478bd9Sstevel@tonic-gate 	}
14667c478bd9Sstevel@tonic-gate 	(void) memcpy(buffer, namestart, namelen);
14677c478bd9Sstevel@tonic-gate 	buffer[namelen] = '\0';
14687c478bd9Sstevel@tonic-gate 	serv->s_name = buffer;
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	while (p < limit && isspace(*p)) {
14717c478bd9Sstevel@tonic-gate 		p++;
14727c478bd9Sstevel@tonic-gate 	}
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 	fieldstart = p;
14757c478bd9Sstevel@tonic-gate 	do {
14767c478bd9Sstevel@tonic-gate 		if (p > limit || isspace(*p)) {
14777c478bd9Sstevel@tonic-gate 			/* Syntax error -- no port/proto */
14787c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
14797c478bd9Sstevel@tonic-gate 		}
14806392794bSMichen Chang 	} while (*p++ != '/');
14817c478bd9Sstevel@tonic-gate 	fieldlen = p - fieldstart - 1;
14827c478bd9Sstevel@tonic-gate 	if (fieldlen == 0 || fieldlen >= sizeof (numbuf)) {
14837c478bd9Sstevel@tonic-gate 		/* Syntax error -- supposed number is empty or too long */
14847c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
14857c478bd9Sstevel@tonic-gate 	}
14867c478bd9Sstevel@tonic-gate 	(void) memcpy(numbuf, fieldstart, fieldlen);
14877c478bd9Sstevel@tonic-gate 	numbuf[fieldlen] = '\0';
14887c478bd9Sstevel@tonic-gate 	serv->s_port = htons((int)strtol(numbuf, &numend, 10));
14897c478bd9Sstevel@tonic-gate 	if (*numend != '\0') {
14907c478bd9Sstevel@tonic-gate 		/* Syntax error -- port number isn't a number */
14917c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
14927c478bd9Sstevel@tonic-gate 	}
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	fieldstart = p;
14957c478bd9Sstevel@tonic-gate 	while (p < limit && !isspace(*p)) {
14967c478bd9Sstevel@tonic-gate 		p++;		/* Scan the protocol name */
14977c478bd9Sstevel@tonic-gate 	}
14987c478bd9Sstevel@tonic-gate 	fieldlen = p - fieldstart + 1;		/* Include '\0' this time */
14997c478bd9Sstevel@tonic-gate 	if (fieldlen > buflen - namelen - 1) {
15007c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
15017c478bd9Sstevel@tonic-gate 	}
15027c478bd9Sstevel@tonic-gate 	serv->s_proto = buffer + namelen + 1;
15037c478bd9Sstevel@tonic-gate 	(void) memcpy(serv->s_proto, fieldstart, fieldlen - 1);
15047c478bd9Sstevel@tonic-gate 	serv->s_proto[fieldlen - 1] = '\0';
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 	while (p < limit && isspace(*p)) {
15077c478bd9Sstevel@tonic-gate 		p++;
15087c478bd9Sstevel@tonic-gate 	}
15097c478bd9Sstevel@tonic-gate 	/*
15107c478bd9Sstevel@tonic-gate 	 * Although nss_files_XY_all calls us with # stripped,
15117c478bd9Sstevel@tonic-gate 	 * we should be able to deal with it here in order to
15127c478bd9Sstevel@tonic-gate 	 * be more useful.
15137c478bd9Sstevel@tonic-gate 	 */
15147c478bd9Sstevel@tonic-gate 	if (p >= limit || *p == '#') { /* no aliases, no problem */
15157c478bd9Sstevel@tonic-gate 		char **ptr;
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 		ptr = (char **)ROUND_UP(buffer + namelen + 1 + fieldlen,
15187c478bd9Sstevel@tonic-gate 		    sizeof (char *));
15197c478bd9Sstevel@tonic-gate 		if ((char *)ptr >= buffer + buflen) {
15207c478bd9Sstevel@tonic-gate 			/* hope they don't try to peek in */
15217c478bd9Sstevel@tonic-gate 			serv->s_aliases = 0;
15227c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_ERANGE);
15237c478bd9Sstevel@tonic-gate 		} else {
15247c478bd9Sstevel@tonic-gate 			*ptr = 0;
15257c478bd9Sstevel@tonic-gate 			serv->s_aliases = ptr;
15267c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
15277c478bd9Sstevel@tonic-gate 		}
15287c478bd9Sstevel@tonic-gate 	}
15297c478bd9Sstevel@tonic-gate 	serv->s_aliases = _nss_netdb_aliases(p, (int)(lenstr - (p - instr)),
15307c478bd9Sstevel@tonic-gate 	    buffer + namelen + 1 + fieldlen,
15317c478bd9Sstevel@tonic-gate 	    (int)(buflen - namelen - 1 - fieldlen));
15327c478bd9Sstevel@tonic-gate 	return (NSS_STR_PARSE_SUCCESS);
15337c478bd9Sstevel@tonic-gate }
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate /*
15367c478bd9Sstevel@tonic-gate  * Part III: All `n sundry routines that are useful only in this
15377c478bd9Sstevel@tonic-gate  * module. In the interest of keeping this source file shorter,
15387c478bd9Sstevel@tonic-gate  * we would create them a new module only if the linker allowed
15397c478bd9Sstevel@tonic-gate  * "library-static" functions.
15407c478bd9Sstevel@tonic-gate  *
15417c478bd9Sstevel@tonic-gate  * Routines to order addresses based on local interfaces and netmasks,
15427c478bd9Sstevel@tonic-gate  * to get and check reserved ports, and to get broadcast nets.
15437c478bd9Sstevel@tonic-gate  */
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate union __v4v6addr {
15467c478bd9Sstevel@tonic-gate 	struct in6_addr	in6;
15477c478bd9Sstevel@tonic-gate 	struct in_addr	in4;
15487c478bd9Sstevel@tonic-gate };
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate struct __ifaddr {
15517c478bd9Sstevel@tonic-gate 	sa_family_t		af;
15527c478bd9Sstevel@tonic-gate 	union __v4v6addr	addr;
15537c478bd9Sstevel@tonic-gate 	union __v4v6addr	mask;
15547c478bd9Sstevel@tonic-gate };
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate struct ifinfo {
15577c478bd9Sstevel@tonic-gate 	int		count;
15587c478bd9Sstevel@tonic-gate 	struct __ifaddr	*addresses;
15597c478bd9Sstevel@tonic-gate };
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate typedef enum {ADDR_ONLINK = 0, ADDR_OFFLINK} addr_class_t;
15627c478bd9Sstevel@tonic-gate #define	ADDR_NUMCLASSES	2
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate typedef enum {IF_ADDR, IF_MASK}	__ifaddr_type;
15657c478bd9Sstevel@tonic-gate static int	__inet_ifassign(sa_family_t, struct __ifaddr *, __ifaddr_type,
15667c478bd9Sstevel@tonic-gate 				void *);
15677c478bd9Sstevel@tonic-gate int		__inet_address_is_local_af(void *, sa_family_t, void *);
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate #define	ifaf(index)	(localinfo->addresses[index].af)
15707c478bd9Sstevel@tonic-gate #define	ifaddr4(index)	(localinfo->addresses[index].addr.in4)
15717c478bd9Sstevel@tonic-gate #define	ifaddr6(index)	(localinfo->addresses[index].addr.in6)
15727c478bd9Sstevel@tonic-gate #define	ifmask4(index)	(localinfo->addresses[index].mask.in4)
15737c478bd9Sstevel@tonic-gate #define	ifmask6(index)	(localinfo->addresses[index].mask.in6)
15747c478bd9Sstevel@tonic-gate #define	ifinfosize(n)	(sizeof (struct ifinfo) + (n)*sizeof (struct __ifaddr))
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate #define	lifraddrp(lifr)	((lifr.lifr_addr.ss_family == AF_INET6) ? \
15777c478bd9Sstevel@tonic-gate 	(void *)&((struct sockaddr_in6 *)&lifr.lifr_addr)->sin6_addr : \
15787c478bd9Sstevel@tonic-gate 	(void *)&((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr)
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate #define	ifassign(lifr, index, type) \
15817c478bd9Sstevel@tonic-gate 			__inet_ifassign(lifr.lifr_addr.ss_family, \
15827c478bd9Sstevel@tonic-gate 				&localinfo->addresses[index], type, \
15837c478bd9Sstevel@tonic-gate 				lifraddrp(lifr))
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate /*
15867c478bd9Sstevel@tonic-gate  * The number of nanoseconds the order_haddrlist_inet() function waits
15877c478bd9Sstevel@tonic-gate  * to retreive IP interface information.  The default is five minutes.
15887c478bd9Sstevel@tonic-gate  */
15897c478bd9Sstevel@tonic-gate #define	IFINFOTIMEOUT	((hrtime_t)300 * NANOSEC)
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate /*
15927c478bd9Sstevel@tonic-gate  * Sort the addresses in haddrlist.  Since the sorting algorithms are
15937c478bd9Sstevel@tonic-gate  * address-family specific, the work is done in the address-family
15947c478bd9Sstevel@tonic-gate  * specific order_haddrlist_<family> functions.
15957c478bd9Sstevel@tonic-gate  *
15967c478bd9Sstevel@tonic-gate  * Do not sort addresses if SORT_ADDRS variable is set to NO or FALSE
15977c478bd9Sstevel@tonic-gate  * in the configuration file /etc/default/nss. This is useful in case
15987c478bd9Sstevel@tonic-gate  * the order of addresses returned by the nameserver needs to be
15997c478bd9Sstevel@tonic-gate  * maintained. (DNS round robin feature is one example)
16007c478bd9Sstevel@tonic-gate  */
16017c478bd9Sstevel@tonic-gate void
order_haddrlist_af(sa_family_t af,char ** haddrlist)16027c478bd9Sstevel@tonic-gate order_haddrlist_af(sa_family_t af, char **haddrlist)
16037c478bd9Sstevel@tonic-gate {
16047c478bd9Sstevel@tonic-gate 	size_t			addrcount;
16057c478bd9Sstevel@tonic-gate 	char			**addrptr;
16067c478bd9Sstevel@tonic-gate 	static boolean_t	checksortcfg = B_TRUE;
16077c478bd9Sstevel@tonic-gate 	static boolean_t	nosort = B_FALSE;
16087c478bd9Sstevel@tonic-gate 	static mutex_t		checksortcfg_lock = DEFAULTMUTEX;
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	if (haddrlist == NULL)
16117c478bd9Sstevel@tonic-gate 		return;
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	/*
16147c478bd9Sstevel@tonic-gate 	 * Check if SORT_ADDRS is set to NO or FALSE in the configuration
16157c478bd9Sstevel@tonic-gate 	 * file.  We do not have to sort addresses in that case.
16167c478bd9Sstevel@tonic-gate 	 */
16177c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&checksortcfg_lock);
16187c478bd9Sstevel@tonic-gate 	if (checksortcfg == B_TRUE) {
16197c478bd9Sstevel@tonic-gate 		checksortcfg = B_FALSE;
16207c478bd9Sstevel@tonic-gate 		nosort = _read_nsw_file();
16217c478bd9Sstevel@tonic-gate 	}
16227c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&checksortcfg_lock);
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate 	if (nosort)
16257c478bd9Sstevel@tonic-gate 		return;
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 	/* Count the addresses to sort */
16287c478bd9Sstevel@tonic-gate 	addrcount = 0;
16297c478bd9Sstevel@tonic-gate 	for (addrptr = haddrlist; *addrptr != NULL; addrptr++)
16307c478bd9Sstevel@tonic-gate 		addrcount++;
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 	/*
16337c478bd9Sstevel@tonic-gate 	 * If there's only one address or no addresses to sort, then
16347c478bd9Sstevel@tonic-gate 	 * there's nothing for us to do.
16357c478bd9Sstevel@tonic-gate 	 */
16367c478bd9Sstevel@tonic-gate 	if (addrcount <= 1)
16377c478bd9Sstevel@tonic-gate 		return;
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 	/* Call the address-family specific sorting functions. */
16407c478bd9Sstevel@tonic-gate 	switch (af) {
16417c478bd9Sstevel@tonic-gate 	case AF_INET:
16427c478bd9Sstevel@tonic-gate 		order_haddrlist_inet(haddrlist, addrcount);
16437c478bd9Sstevel@tonic-gate 		break;
16447c478bd9Sstevel@tonic-gate 	case AF_INET6:
16457c478bd9Sstevel@tonic-gate 		order_haddrlist_inet6(haddrlist, addrcount);
16467c478bd9Sstevel@tonic-gate 		break;
16477c478bd9Sstevel@tonic-gate 	default:
16487c478bd9Sstevel@tonic-gate 		break;
16497c478bd9Sstevel@tonic-gate 	}
16507c478bd9Sstevel@tonic-gate }
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate /*
16537c478bd9Sstevel@tonic-gate  * Move any local (on-link) addresses toward the beginning of haddrlist.
16547c478bd9Sstevel@tonic-gate  * The order within these two classes is preserved.
16557c478bd9Sstevel@tonic-gate  *
16567c478bd9Sstevel@tonic-gate  * The interface list is retrieved no more often than every
16577c478bd9Sstevel@tonic-gate  * IFINFOTIMEOUT nanoseconds. Access to the interface list is
16587c478bd9Sstevel@tonic-gate  * protected by an RW lock.
16597c478bd9Sstevel@tonic-gate  *
16607c478bd9Sstevel@tonic-gate  * If this function encounters an error, haddrlist is unaltered.
16617c478bd9Sstevel@tonic-gate  */
16627c478bd9Sstevel@tonic-gate static void
order_haddrlist_inet(char ** haddrlist,size_t addrcount)16637c478bd9Sstevel@tonic-gate order_haddrlist_inet(char **haddrlist, size_t addrcount)
16647c478bd9Sstevel@tonic-gate {
16657c478bd9Sstevel@tonic-gate 	static struct	ifinfo *localinfo = NULL;
16667c478bd9Sstevel@tonic-gate 	static hrtime_t	then = 0; /* the last time localinfo was updated */
16677c478bd9Sstevel@tonic-gate 	hrtime_t	now;
16687c478bd9Sstevel@tonic-gate 	static rwlock_t	localinfo_lock = DEFAULTRWLOCK;
16697c478bd9Sstevel@tonic-gate 	uint8_t		*sortbuf;
16707c478bd9Sstevel@tonic-gate 	size_t		sortbuf_size;
16717c478bd9Sstevel@tonic-gate 	struct in_addr	**inaddrlist = (struct in_addr **)haddrlist;
16727c478bd9Sstevel@tonic-gate 	struct in_addr	**sorted;
16737c478bd9Sstevel@tonic-gate 	struct in_addr	**classnext[ADDR_NUMCLASSES];
16747c478bd9Sstevel@tonic-gate 	uint_t		classcount[ADDR_NUMCLASSES];
16757c478bd9Sstevel@tonic-gate 	addr_class_t	*sortclass;
16767c478bd9Sstevel@tonic-gate 	int		i;
16777c478bd9Sstevel@tonic-gate 	int		rc;
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	/*
16817c478bd9Sstevel@tonic-gate 	 * The classes in the sortclass array correspond to the class
16827c478bd9Sstevel@tonic-gate 	 * of the address in the haddrlist list of the same index.
16837c478bd9Sstevel@tonic-gate 	 * The classes are:
16847c478bd9Sstevel@tonic-gate 	 *
16857c478bd9Sstevel@tonic-gate 	 * ADDR_ONLINK	on-link address
16867c478bd9Sstevel@tonic-gate 	 * ADDR_OFFLINK	off-link address
16877c478bd9Sstevel@tonic-gate 	 */
16887c478bd9Sstevel@tonic-gate 	sortbuf_size = addrcount *
16897c478bd9Sstevel@tonic-gate 	    (sizeof (struct in_addr *) + sizeof (addr_class_t));
16907c478bd9Sstevel@tonic-gate 	if ((sortbuf = malloc(sortbuf_size)) == NULL)
16917c478bd9Sstevel@tonic-gate 		return;
169261961e0fSrobinson 	/* LINTED pointer cast */
16937c478bd9Sstevel@tonic-gate 	sorted = (struct in_addr **)sortbuf;
169461961e0fSrobinson 	/* LINTED pointer cast */
16957c478bd9Sstevel@tonic-gate 	sortclass = (addr_class_t *)(sortbuf +
16967c478bd9Sstevel@tonic-gate 	    (addrcount * sizeof (struct in_addr *)));
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate 	/*
16997c478bd9Sstevel@tonic-gate 	 * Get a read lock, and check if the interface information
17007c478bd9Sstevel@tonic-gate 	 * is too old.
17017c478bd9Sstevel@tonic-gate 	 */
17027c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&localinfo_lock);
17037c478bd9Sstevel@tonic-gate 	now = gethrtime();
17047c478bd9Sstevel@tonic-gate 	if (localinfo == NULL || ((now - then) > IFINFOTIMEOUT)) {
17057c478bd9Sstevel@tonic-gate 		/* Need to update I/F info. Upgrade to write lock. */
17067c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&localinfo_lock);
17077c478bd9Sstevel@tonic-gate 		(void) rw_wrlock(&localinfo_lock);
17087c478bd9Sstevel@tonic-gate 		/*
17097c478bd9Sstevel@tonic-gate 		 * Another thread might have updated "then" between
17107c478bd9Sstevel@tonic-gate 		 * the rw_unlock() and rw_wrlock() calls above, so
17117c478bd9Sstevel@tonic-gate 		 * re-check the timeout.
17127c478bd9Sstevel@tonic-gate 		 */
17137c478bd9Sstevel@tonic-gate 		if (localinfo == NULL || ((now - then) > IFINFOTIMEOUT)) {
17147c478bd9Sstevel@tonic-gate 			if (localinfo != NULL)
17157c478bd9Sstevel@tonic-gate 				free(localinfo);
17167c478bd9Sstevel@tonic-gate 			if ((localinfo = get_local_info()) == NULL) {
17177c478bd9Sstevel@tonic-gate 				(void) rw_unlock(&localinfo_lock);
17187c478bd9Sstevel@tonic-gate 				free(sortbuf);
17197c478bd9Sstevel@tonic-gate 				return;
17207c478bd9Sstevel@tonic-gate 			}
17217c478bd9Sstevel@tonic-gate 			then = now;
17227c478bd9Sstevel@tonic-gate 		}
17237c478bd9Sstevel@tonic-gate 		/* Downgrade to read lock */
17247c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&localinfo_lock);
17257c478bd9Sstevel@tonic-gate 		(void) rw_rdlock(&localinfo_lock);
17267c478bd9Sstevel@tonic-gate 		/*
17277c478bd9Sstevel@tonic-gate 		 * Another thread may have updated the I/F info,
17287c478bd9Sstevel@tonic-gate 		 * so verify that the 'localinfo' pointer still
17297c478bd9Sstevel@tonic-gate 		 * is non-NULL.
17307c478bd9Sstevel@tonic-gate 		 */
17317c478bd9Sstevel@tonic-gate 		if (localinfo == NULL) {
17327c478bd9Sstevel@tonic-gate 			(void) rw_unlock(&localinfo_lock);
17337c478bd9Sstevel@tonic-gate 			free(sortbuf);
17347c478bd9Sstevel@tonic-gate 			return;
17357c478bd9Sstevel@tonic-gate 		}
17367c478bd9Sstevel@tonic-gate 	}
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	/*
17397c478bd9Sstevel@tonic-gate 	 * Classify the addresses.  We also maintain the classcount
17407c478bd9Sstevel@tonic-gate 	 * array to keep track of the number of addresses in each
17417c478bd9Sstevel@tonic-gate 	 * class.
17427c478bd9Sstevel@tonic-gate 	 */
174361961e0fSrobinson 	(void) memset(classcount, 0, sizeof (classcount));
17447c478bd9Sstevel@tonic-gate 	for (i = 0; i < addrcount; i++) {
17457c478bd9Sstevel@tonic-gate 		if (__inet_address_is_local_af(localinfo, AF_INET,
17467c478bd9Sstevel@tonic-gate 		    inaddrlist[i]))
17477c478bd9Sstevel@tonic-gate 			sortclass[i] = ADDR_ONLINK;
17487c478bd9Sstevel@tonic-gate 		else
17497c478bd9Sstevel@tonic-gate 			sortclass[i] = ADDR_OFFLINK;
17507c478bd9Sstevel@tonic-gate 		classcount[sortclass[i]]++;
17517c478bd9Sstevel@tonic-gate 	}
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	/* Don't need the interface list anymore in this call */
17547c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&localinfo_lock);
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 	/*
17577c478bd9Sstevel@tonic-gate 	 * Each element in the classnext array points to the next
17587c478bd9Sstevel@tonic-gate 	 * element for that class in the sorted address list. 'rc' is
17597c478bd9Sstevel@tonic-gate 	 * the running count of elements as we sum the class
17607c478bd9Sstevel@tonic-gate 	 * sub-totals.
17617c478bd9Sstevel@tonic-gate 	 */
17627c478bd9Sstevel@tonic-gate 	for (rc = 0, i = 0; i < ADDR_NUMCLASSES; i++) {
17637c478bd9Sstevel@tonic-gate 		classnext[i] = &sorted[rc];
17647c478bd9Sstevel@tonic-gate 		rc += classcount[i];
17657c478bd9Sstevel@tonic-gate 	}
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 	/* Now for the actual rearrangement of the addresses */
17687c478bd9Sstevel@tonic-gate 	for (i = 0; i < addrcount; i++) {
17697c478bd9Sstevel@tonic-gate 		*(classnext[sortclass[i]]) = inaddrlist[i];
17707c478bd9Sstevel@tonic-gate 		classnext[sortclass[i]]++;
17717c478bd9Sstevel@tonic-gate 	}
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	/* Copy the sorted list to inaddrlist */
17747c478bd9Sstevel@tonic-gate 	(void) memcpy(inaddrlist, sorted,
17757c478bd9Sstevel@tonic-gate 	    addrcount * sizeof (struct in_addr *));
17767c478bd9Sstevel@tonic-gate 	free(sortbuf);
17777c478bd9Sstevel@tonic-gate }
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate /*
17807c478bd9Sstevel@tonic-gate  * This function implements the IPv6 Default Address Selection's
17817c478bd9Sstevel@tonic-gate  * destination address ordering mechanism.  The algorithm is described
17827c478bd9Sstevel@tonic-gate  * in getaddrinfo(3SOCKET).
17837c478bd9Sstevel@tonic-gate  */
17847c478bd9Sstevel@tonic-gate static void
order_haddrlist_inet6(char ** haddrlist,size_t addrcount)17857c478bd9Sstevel@tonic-gate order_haddrlist_inet6(char **haddrlist, size_t addrcount)
17867c478bd9Sstevel@tonic-gate {
17877c478bd9Sstevel@tonic-gate 	struct dstinforeq *dinfo, *dinfoptr;
17887c478bd9Sstevel@tonic-gate 	struct in6_addr **in6addrlist = (struct in6_addr **)haddrlist;
17897c478bd9Sstevel@tonic-gate 	struct in6_addr	**in6addr;
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	if ((dinfo = calloc(addrcount, sizeof (struct dstinforeq))) == NULL)
17927c478bd9Sstevel@tonic-gate 		return;
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 	/* Initialize the dstinfo array we'll use for SIOCGDSTINFO */
17957c478bd9Sstevel@tonic-gate 	dinfoptr = dinfo;
17967c478bd9Sstevel@tonic-gate 	for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) {
17977c478bd9Sstevel@tonic-gate 		dinfoptr->dir_daddr = **in6addr;
17987c478bd9Sstevel@tonic-gate 		dinfoptr++;
17997c478bd9Sstevel@tonic-gate 	}
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate 	if (nss_strioctl(AF_INET6, SIOCGDSTINFO, dinfo,
18027c478bd9Sstevel@tonic-gate 	    addrcount * sizeof (struct dstinforeq)) < 0) {
18037c478bd9Sstevel@tonic-gate 		free(dinfo);
18047c478bd9Sstevel@tonic-gate 		return;
18057c478bd9Sstevel@tonic-gate 	}
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate 	/* Sort the dinfo array */
18087c478bd9Sstevel@tonic-gate 	qsort(dinfo, addrcount, sizeof (struct dstinforeq), dstcmp);
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	/* Copy the addresses back into in6addrlist */
18117c478bd9Sstevel@tonic-gate 	dinfoptr = dinfo;
18127c478bd9Sstevel@tonic-gate 	for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) {
18137c478bd9Sstevel@tonic-gate 		**in6addr = dinfoptr->dir_daddr;
18147c478bd9Sstevel@tonic-gate 		dinfoptr++;
18157c478bd9Sstevel@tonic-gate 	}
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 	free(dinfo);
18187c478bd9Sstevel@tonic-gate }
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate /*
18217c478bd9Sstevel@tonic-gate  * Determine number of leading bits that are common between two addresses.
18227c478bd9Sstevel@tonic-gate  * Only consider bits which fall within the prefix length plen.
18237c478bd9Sstevel@tonic-gate  */
18247c478bd9Sstevel@tonic-gate static uint_t
ip_addr_commonbits_v6(const in6_addr_t * a1,const in6_addr_t * a2)18257c478bd9Sstevel@tonic-gate ip_addr_commonbits_v6(const in6_addr_t *a1, const in6_addr_t *a2)
18267c478bd9Sstevel@tonic-gate {
18277c478bd9Sstevel@tonic-gate 	uint_t		bits;
18287c478bd9Sstevel@tonic-gate 	uint_t		i;
18297c478bd9Sstevel@tonic-gate 	uint32_t	diff;	/* Bits that differ */
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	for (i = 0; i < 4; i++) {
18327c478bd9Sstevel@tonic-gate 		if (a1->_S6_un._S6_u32[i] != a2->_S6_un._S6_u32[i])
18337c478bd9Sstevel@tonic-gate 			break;
18347c478bd9Sstevel@tonic-gate 	}
18357c478bd9Sstevel@tonic-gate 	bits = i * 32;
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	if (bits == IPV6_ABITS)
18387c478bd9Sstevel@tonic-gate 		return (IPV6_ABITS);
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate 	/*
18417c478bd9Sstevel@tonic-gate 	 * Find number of leading common bits in the word which might
18427c478bd9Sstevel@tonic-gate 	 * have some common bits by searching for the first one from the left
18437c478bd9Sstevel@tonic-gate 	 * in the xor of the two addresses.
18447c478bd9Sstevel@tonic-gate 	 */
18457c478bd9Sstevel@tonic-gate 	diff = ntohl(a1->_S6_un._S6_u32[i] ^ a2->_S6_un._S6_u32[i]);
18467c478bd9Sstevel@tonic-gate 	if (diff & 0xffff0000ul)
18477c478bd9Sstevel@tonic-gate 		diff >>= 16;
18487c478bd9Sstevel@tonic-gate 	else
18497c478bd9Sstevel@tonic-gate 		bits += 16;
18507c478bd9Sstevel@tonic-gate 	if (diff & 0xff00)
18517c478bd9Sstevel@tonic-gate 		diff >>= 8;
18527c478bd9Sstevel@tonic-gate 	else
18537c478bd9Sstevel@tonic-gate 		bits += 8;
18547c478bd9Sstevel@tonic-gate 	if (diff & 0xf0)
18557c478bd9Sstevel@tonic-gate 		diff >>= 4;
18567c478bd9Sstevel@tonic-gate 	else
18577c478bd9Sstevel@tonic-gate 		bits += 4;
18587c478bd9Sstevel@tonic-gate 	if (diff & 0xc)
18597c478bd9Sstevel@tonic-gate 		diff >>= 2;
18607c478bd9Sstevel@tonic-gate 	else
18617c478bd9Sstevel@tonic-gate 		bits += 2;
18627c478bd9Sstevel@tonic-gate 	if (!(diff & 2))
18637c478bd9Sstevel@tonic-gate 		bits++;
18647c478bd9Sstevel@tonic-gate 
18657c478bd9Sstevel@tonic-gate 	/*
18667c478bd9Sstevel@tonic-gate 	 * We don't need to shift and check for the last bit.  The
18677c478bd9Sstevel@tonic-gate 	 * check for IPV6_ABITS above would have caught that.
18687c478bd9Sstevel@tonic-gate 	 */
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 	return (bits);
18717c478bd9Sstevel@tonic-gate }
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate 
18747c478bd9Sstevel@tonic-gate /*
18757c478bd9Sstevel@tonic-gate  * The following group of functions named rule_*() are individual
18767c478bd9Sstevel@tonic-gate  * sorting rules for the AF_INET6 address sorting algorithm.  The
18777c478bd9Sstevel@tonic-gate  * functions compare two addresses (described by two dstinforeq
18787c478bd9Sstevel@tonic-gate  * structures), and determines if one is "greater" than the other, or
18797c478bd9Sstevel@tonic-gate  * if the two are equal according to that rule.
18807c478bd9Sstevel@tonic-gate  */
18817c478bd9Sstevel@tonic-gate typedef	int (*rulef_t)(const struct dstinforeq *, const struct dstinforeq *);
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate /*
18847c478bd9Sstevel@tonic-gate  * These values of these constants are no accident.  Since qsort()
18857c478bd9Sstevel@tonic-gate  * implements the AF_INET6 address sorting, the comparison function
18867c478bd9Sstevel@tonic-gate  * must return an integer less than, equal to, or greater than zero to
18877c478bd9Sstevel@tonic-gate  * indicate if the first address is considered "less than", "equal
18887c478bd9Sstevel@tonic-gate  * to", or "greater than" the second one.  Since we want the best
18897c478bd9Sstevel@tonic-gate  * addresses first on the list, "less than" is considered preferrable.
18907c478bd9Sstevel@tonic-gate  */
18917c478bd9Sstevel@tonic-gate #define	RULE_PREFER_DA	-1
18927c478bd9Sstevel@tonic-gate #define	RULE_PREFER_DB	1
18937c478bd9Sstevel@tonic-gate #define	RULE_EQUAL	0
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate /* Prefer the addresses that is reachable. */
18967c478bd9Sstevel@tonic-gate static int
rule_reachable(const struct dstinforeq * da,const struct dstinforeq * db)18977c478bd9Sstevel@tonic-gate rule_reachable(const struct dstinforeq *da, const struct dstinforeq *db)
18987c478bd9Sstevel@tonic-gate {
18997c478bd9Sstevel@tonic-gate 	if (da->dir_dreachable == db->dir_dreachable)
19007c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
19017c478bd9Sstevel@tonic-gate 	if (da->dir_dreachable)
19027c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19037c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19047c478bd9Sstevel@tonic-gate }
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate /* Prefer the address whose scope matches that of its source address. */
19077c478bd9Sstevel@tonic-gate static int
rule_matchscope(const struct dstinforeq * da,const struct dstinforeq * db)19087c478bd9Sstevel@tonic-gate rule_matchscope(const struct dstinforeq *da, const struct dstinforeq *db)
19097c478bd9Sstevel@tonic-gate {
19107c478bd9Sstevel@tonic-gate 	boolean_t da_scope_match, db_scope_match;
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	da_scope_match = da->dir_dscope == da->dir_sscope;
19137c478bd9Sstevel@tonic-gate 	db_scope_match = db->dir_dscope == db->dir_sscope;
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 	if (da_scope_match == db_scope_match)
19167c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
19177c478bd9Sstevel@tonic-gate 	if (da_scope_match)
19187c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19197c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19207c478bd9Sstevel@tonic-gate }
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate /* Avoid the address with the link local source address. */
19237c478bd9Sstevel@tonic-gate static int
rule_avoidlinklocal(const struct dstinforeq * da,const struct dstinforeq * db)19247c478bd9Sstevel@tonic-gate rule_avoidlinklocal(const struct dstinforeq *da, const struct dstinforeq *db)
19257c478bd9Sstevel@tonic-gate {
19267c478bd9Sstevel@tonic-gate 	if (da->dir_sscope == IP6_SCOPE_LINKLOCAL &&
19277c478bd9Sstevel@tonic-gate 	    da->dir_dscope != IP6_SCOPE_LINKLOCAL &&
19287c478bd9Sstevel@tonic-gate 	    db->dir_sscope != IP6_SCOPE_LINKLOCAL)
19297c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DB);
19307c478bd9Sstevel@tonic-gate 	if (db->dir_sscope == IP6_SCOPE_LINKLOCAL &&
19317c478bd9Sstevel@tonic-gate 	    db->dir_dscope != IP6_SCOPE_LINKLOCAL &&
19327c478bd9Sstevel@tonic-gate 	    da->dir_sscope != IP6_SCOPE_LINKLOCAL)
19337c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19347c478bd9Sstevel@tonic-gate 	return (RULE_EQUAL);
19357c478bd9Sstevel@tonic-gate }
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate /* Prefer the address whose source address isn't deprecated. */
19387c478bd9Sstevel@tonic-gate static int
rule_deprecated(const struct dstinforeq * da,const struct dstinforeq * db)19397c478bd9Sstevel@tonic-gate rule_deprecated(const struct dstinforeq *da, const struct dstinforeq *db)
19407c478bd9Sstevel@tonic-gate {
19417c478bd9Sstevel@tonic-gate 	if (da->dir_sdeprecated == db->dir_sdeprecated)
19427c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
19437c478bd9Sstevel@tonic-gate 	if (db->dir_sdeprecated)
19447c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19457c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19467c478bd9Sstevel@tonic-gate }
19477c478bd9Sstevel@tonic-gate 
19487c478bd9Sstevel@tonic-gate /* Prefer the address whose label matches that of its source address. */
19497c478bd9Sstevel@tonic-gate static int
rule_label(const struct dstinforeq * da,const struct dstinforeq * db)19507c478bd9Sstevel@tonic-gate rule_label(const struct dstinforeq *da, const struct dstinforeq *db)
19517c478bd9Sstevel@tonic-gate {
19527c478bd9Sstevel@tonic-gate 	if (da->dir_labelmatch == db->dir_labelmatch)
19537c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
19547c478bd9Sstevel@tonic-gate 	if (da->dir_labelmatch)
19557c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19567c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19577c478bd9Sstevel@tonic-gate }
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate /* Prefer the address with the higher precedence. */
19607c478bd9Sstevel@tonic-gate static int
rule_precedence(const struct dstinforeq * da,const struct dstinforeq * db)19617c478bd9Sstevel@tonic-gate rule_precedence(const struct dstinforeq *da, const struct dstinforeq *db)
19627c478bd9Sstevel@tonic-gate {
19637c478bd9Sstevel@tonic-gate 	if (da->dir_precedence == db->dir_precedence)
19647c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
19657c478bd9Sstevel@tonic-gate 	if (da->dir_precedence > db->dir_precedence)
19667c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19677c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19687c478bd9Sstevel@tonic-gate }
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate /* Prefer the address whose output interface isn't an IP tunnel */
19717c478bd9Sstevel@tonic-gate static int
rule_native(const struct dstinforeq * da,const struct dstinforeq * db)19727c478bd9Sstevel@tonic-gate rule_native(const struct dstinforeq *da, const struct dstinforeq *db)
19737c478bd9Sstevel@tonic-gate {
19747c478bd9Sstevel@tonic-gate 	boolean_t isatun, isbtun;
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 	/* Get the common case out of the way early */
19777c478bd9Sstevel@tonic-gate 	if (da->dir_dmactype == db->dir_dmactype)
19787c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 	isatun = da->dir_dmactype == DL_IPV4 || da->dir_dmactype == DL_IPV6;
19817c478bd9Sstevel@tonic-gate 	isbtun = db->dir_dmactype == DL_IPV4 || db->dir_dmactype == DL_IPV6;
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate 	if (isatun == isbtun)
19847c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
19857c478bd9Sstevel@tonic-gate 	if (isbtun)
19867c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19877c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19887c478bd9Sstevel@tonic-gate }
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate /* Prefer the address with the smaller scope. */
19917c478bd9Sstevel@tonic-gate static int
rule_scope(const struct dstinforeq * da,const struct dstinforeq * db)19927c478bd9Sstevel@tonic-gate rule_scope(const struct dstinforeq *da, const struct dstinforeq *db)
19937c478bd9Sstevel@tonic-gate {
19947c478bd9Sstevel@tonic-gate 	if (da->dir_dscope == db->dir_dscope)
19957c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
19967c478bd9Sstevel@tonic-gate 	if (da->dir_dscope < db->dir_dscope)
19977c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
19987c478bd9Sstevel@tonic-gate 	return (RULE_PREFER_DB);
19997c478bd9Sstevel@tonic-gate }
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate /*
20027c478bd9Sstevel@tonic-gate  * Prefer the address that has the most leading bits in common with its
20037c478bd9Sstevel@tonic-gate  * source address.
20047c478bd9Sstevel@tonic-gate  */
20057c478bd9Sstevel@tonic-gate static int
rule_prefix(const struct dstinforeq * da,const struct dstinforeq * db)20067c478bd9Sstevel@tonic-gate rule_prefix(const struct dstinforeq *da, const struct dstinforeq *db)
20077c478bd9Sstevel@tonic-gate {
20087c478bd9Sstevel@tonic-gate 	uint_t da_commonbits, db_commonbits;
20097c478bd9Sstevel@tonic-gate 	boolean_t da_isipv4, db_isipv4;
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate 	da_isipv4 = IN6_IS_ADDR_V4MAPPED(&da->dir_daddr);
20127c478bd9Sstevel@tonic-gate 	db_isipv4 = IN6_IS_ADDR_V4MAPPED(&db->dir_daddr);
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 	/*
20157c478bd9Sstevel@tonic-gate 	 * At this point, the order doesn't matter if the two addresses
20167c478bd9Sstevel@tonic-gate 	 * aren't of the same address family.
20177c478bd9Sstevel@tonic-gate 	 */
20187c478bd9Sstevel@tonic-gate 	if (da_isipv4 != db_isipv4)
20197c478bd9Sstevel@tonic-gate 		return (RULE_EQUAL);
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate 	da_commonbits = ip_addr_commonbits_v6(&da->dir_daddr, &da->dir_saddr);
20227c478bd9Sstevel@tonic-gate 	db_commonbits = ip_addr_commonbits_v6(&db->dir_daddr, &db->dir_saddr);
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate 	if (da_commonbits > db_commonbits)
20257c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DA);
20267c478bd9Sstevel@tonic-gate 	if (da_commonbits < db_commonbits)
20277c478bd9Sstevel@tonic-gate 		return (RULE_PREFER_DB);
20287c478bd9Sstevel@tonic-gate 	return (RULE_EQUAL);
20297c478bd9Sstevel@tonic-gate }
20307c478bd9Sstevel@tonic-gate 
20317c478bd9Sstevel@tonic-gate /*
20327c478bd9Sstevel@tonic-gate  * This is the function passed to qsort() that does the AF_INET6
20337c478bd9Sstevel@tonic-gate  * address comparisons.  It compares two addresses using a list of
20347c478bd9Sstevel@tonic-gate  * rules.  The rules are applied in order until one prefers one
20357c478bd9Sstevel@tonic-gate  * address over the other.
20367c478bd9Sstevel@tonic-gate  */
20377c478bd9Sstevel@tonic-gate static int
dstcmp(const void * da,const void * db)20387c478bd9Sstevel@tonic-gate dstcmp(const void *da, const void *db)
20397c478bd9Sstevel@tonic-gate {
20407c478bd9Sstevel@tonic-gate 	int index, result;
20417c478bd9Sstevel@tonic-gate 	rulef_t rules[] = {
20426392794bSMichen Chang 	    rule_reachable,
20436392794bSMichen Chang 	    rule_matchscope,
20446392794bSMichen Chang 	    rule_avoidlinklocal,
20456392794bSMichen Chang 	    rule_deprecated,
20466392794bSMichen Chang 	    rule_label,
20476392794bSMichen Chang 	    rule_precedence,
20486392794bSMichen Chang 	    rule_native,
20496392794bSMichen Chang 	    rule_scope,
20506392794bSMichen Chang 	    rule_prefix,
20516392794bSMichen Chang 	    NULL
20527c478bd9Sstevel@tonic-gate 	};
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate 	result = 0;
20557c478bd9Sstevel@tonic-gate 	for (index = 0; rules[index] != NULL; index++) {
20567c478bd9Sstevel@tonic-gate 		result = (rules[index])(da, db);
20577c478bd9Sstevel@tonic-gate 		if (result != RULE_EQUAL)
20587c478bd9Sstevel@tonic-gate 			break;
20597c478bd9Sstevel@tonic-gate 	}
20607c478bd9Sstevel@tonic-gate 
20617c478bd9Sstevel@tonic-gate 	return (result);
20627c478bd9Sstevel@tonic-gate }
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate /*
20657c478bd9Sstevel@tonic-gate  * Given haddrlist and a port number, mallocs and populates a new
20667c478bd9Sstevel@tonic-gate  * nd_addrlist.  The new nd_addrlist maintains the order of the addresses
20677c478bd9Sstevel@tonic-gate  * in haddrlist, which have already been sorted by order_haddrlist_inet()
20687c478bd9Sstevel@tonic-gate  * or order_haddrlist_inet6().  For IPv6 this function filters out
20697c478bd9Sstevel@tonic-gate  * IPv4-mapped IPv6 addresses.
20707c478bd9Sstevel@tonic-gate  */
20717c478bd9Sstevel@tonic-gate int
hent2ndaddr(int af,char ** haddrlist,int * servp,struct nd_addrlist ** nd_alist)20727c478bd9Sstevel@tonic-gate hent2ndaddr(int af, char **haddrlist, int *servp, struct nd_addrlist **nd_alist)
20737c478bd9Sstevel@tonic-gate {
20747c478bd9Sstevel@tonic-gate 	struct nd_addrlist	*result;
20757c478bd9Sstevel@tonic-gate 	int			num;
20767c478bd9Sstevel@tonic-gate 	struct netbuf		*na;
20777c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sinbuf, *sin;
20787c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6buf, *sin6;
20797c478bd9Sstevel@tonic-gate 	struct in_addr		**inaddr, **inaddrlist;
20807c478bd9Sstevel@tonic-gate 	struct in6_addr		**in6addr, **in6addrlist;
20817c478bd9Sstevel@tonic-gate 
20827c478bd9Sstevel@tonic-gate 	/* Address count */
20837c478bd9Sstevel@tonic-gate 	num = 0;
20847c478bd9Sstevel@tonic-gate 	if (af == AF_INET6) {
20857c478bd9Sstevel@tonic-gate 		in6addrlist = (struct in6_addr **)haddrlist;
20867c478bd9Sstevel@tonic-gate 
20877c478bd9Sstevel@tonic-gate 		/*
20887c478bd9Sstevel@tonic-gate 		 * Exclude IPv4-mapped IPv6 addresses from the count, as
20897c478bd9Sstevel@tonic-gate 		 * these are not included in the nd_addrlist we return.
20907c478bd9Sstevel@tonic-gate 		 */
20917c478bd9Sstevel@tonic-gate 		for (in6addr = in6addrlist; *in6addr != NULL; in6addr++)
20927c478bd9Sstevel@tonic-gate 			if (!IN6_IS_ADDR_V4MAPPED(*in6addr))
20937c478bd9Sstevel@tonic-gate 				num++;
20947c478bd9Sstevel@tonic-gate 	} else {
20957c478bd9Sstevel@tonic-gate 		inaddrlist = (struct in_addr **)haddrlist;
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate 		for (inaddr = inaddrlist; *inaddr != NULL; inaddr++)
20987c478bd9Sstevel@tonic-gate 			num++;
20997c478bd9Sstevel@tonic-gate 	}
21007c478bd9Sstevel@tonic-gate 	if (num == 0)
21017c478bd9Sstevel@tonic-gate 		return (ND_NOHOST);
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate 	result = malloc(sizeof (struct nd_addrlist));
21047c478bd9Sstevel@tonic-gate 	if (result == 0)
21057c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 	result->n_cnt = num;
21087c478bd9Sstevel@tonic-gate 	result->n_addrs = calloc(num, sizeof (struct netbuf));
21097c478bd9Sstevel@tonic-gate 	if (result->n_addrs == 0) {
21107c478bd9Sstevel@tonic-gate 		free(result);
21117c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
21127c478bd9Sstevel@tonic-gate 	}
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate 	na = result->n_addrs;
21157c478bd9Sstevel@tonic-gate 	if (af == AF_INET) {
21167c478bd9Sstevel@tonic-gate 		sinbuf = calloc(num, sizeof (struct sockaddr_in));
21177c478bd9Sstevel@tonic-gate 		if (sinbuf == NULL) {
21187c478bd9Sstevel@tonic-gate 			free(result->n_addrs);
21197c478bd9Sstevel@tonic-gate 			free(result);
21207c478bd9Sstevel@tonic-gate 			return (ND_NOMEM);
21217c478bd9Sstevel@tonic-gate 		}
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate 		sin = sinbuf;
21247c478bd9Sstevel@tonic-gate 		for (inaddr = inaddrlist; *inaddr != NULL; inaddr++) {
21257c478bd9Sstevel@tonic-gate 			na->len = na->maxlen = sizeof (struct sockaddr_in);
21267c478bd9Sstevel@tonic-gate 			na->buf = (char *)sin;
21277c478bd9Sstevel@tonic-gate 			sin->sin_family = AF_INET;
21287c478bd9Sstevel@tonic-gate 			sin->sin_addr = **inaddr;
21297c478bd9Sstevel@tonic-gate 			sin->sin_port = *servp;
21307c478bd9Sstevel@tonic-gate 			na++;
21317c478bd9Sstevel@tonic-gate 			sin++;
21327c478bd9Sstevel@tonic-gate 		}
21337c478bd9Sstevel@tonic-gate 	} else if (af == AF_INET6) {
21347c478bd9Sstevel@tonic-gate 		sin6buf = calloc(num, sizeof (struct sockaddr_in6));
21357c478bd9Sstevel@tonic-gate 		if (sin6buf == NULL) {
21367c478bd9Sstevel@tonic-gate 			free(result->n_addrs);
21377c478bd9Sstevel@tonic-gate 			free(result);
21387c478bd9Sstevel@tonic-gate 			return (ND_NOMEM);
21397c478bd9Sstevel@tonic-gate 		}
21407c478bd9Sstevel@tonic-gate 
21417c478bd9Sstevel@tonic-gate 		sin6 = sin6buf;
21427c478bd9Sstevel@tonic-gate 		for (in6addr = in6addrlist; *in6addr != NULL; in6addr++) {
21437c478bd9Sstevel@tonic-gate 			if (IN6_IS_ADDR_V4MAPPED(*in6addr))
21447c478bd9Sstevel@tonic-gate 				continue;
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 			na->len = na->maxlen = sizeof (struct sockaddr_in6);
21477c478bd9Sstevel@tonic-gate 			na->buf = (char *)sin6;
21487c478bd9Sstevel@tonic-gate 			sin6->sin6_family = AF_INET6;
21497c478bd9Sstevel@tonic-gate 			sin6->sin6_addr = **in6addr;
21507c478bd9Sstevel@tonic-gate 			sin6->sin6_port = *servp;
21517c478bd9Sstevel@tonic-gate 			na++;
21527c478bd9Sstevel@tonic-gate 			sin6++;
21537c478bd9Sstevel@tonic-gate 		}
21547c478bd9Sstevel@tonic-gate 	}
21557c478bd9Sstevel@tonic-gate 	*(nd_alist) = result;
21567c478bd9Sstevel@tonic-gate 	return (ND_OK);
21577c478bd9Sstevel@tonic-gate }
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate /*
21607c478bd9Sstevel@tonic-gate  * Given a hostent and a servent, mallocs and populates
21617c478bd9Sstevel@tonic-gate  * a new nd_hostservlist with host and service names.
21627c478bd9Sstevel@tonic-gate  *
21637c478bd9Sstevel@tonic-gate  * We could be passed in a NULL servent, in which case stringify port.
21647c478bd9Sstevel@tonic-gate  */
21657c478bd9Sstevel@tonic-gate int
hsents2ndhostservs(struct hostent * he,struct servent * se,ushort_t port,struct nd_hostservlist ** hslist)21667c478bd9Sstevel@tonic-gate hsents2ndhostservs(struct hostent *he, struct servent *se,
21677c478bd9Sstevel@tonic-gate     ushort_t port, struct nd_hostservlist **hslist)
21687c478bd9Sstevel@tonic-gate {
21697c478bd9Sstevel@tonic-gate 	struct	nd_hostservlist *result;
21707c478bd9Sstevel@tonic-gate 	struct	nd_hostserv *hs;
21717c478bd9Sstevel@tonic-gate 	int	hosts, servs, i, j;
21727c478bd9Sstevel@tonic-gate 	char	**hn, **sn;
21737c478bd9Sstevel@tonic-gate 
217461961e0fSrobinson 	if ((result = malloc(sizeof (struct nd_hostservlist))) == 0)
21757c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate 	/*
21787c478bd9Sstevel@tonic-gate 	 * We initialize the counters to 1 rather than zero because
21797c478bd9Sstevel@tonic-gate 	 * we have to count the "official" name as well as the aliases.
21807c478bd9Sstevel@tonic-gate 	 */
21816392794bSMichen Chang 	for (hn = he->h_aliases, hosts = 1; hn && *hn; hn++, hosts++) {};
21826392794bSMichen Chang 	if (se) {
21836392794bSMichen Chang 		for (sn = se->s_aliases, servs = 1; sn && *sn; sn++, servs++) {
21846392794bSMichen Chang 		};
21856392794bSMichen Chang 	} else
21867c478bd9Sstevel@tonic-gate 		servs = 1;
21877c478bd9Sstevel@tonic-gate 
218861961e0fSrobinson 	if ((hs = calloc(hosts * servs, sizeof (struct nd_hostserv))) == 0) {
218961961e0fSrobinson 		free(result);
21907c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
21917c478bd9Sstevel@tonic-gate 	}
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 	result->h_cnt	= servs * hosts;
21947c478bd9Sstevel@tonic-gate 	result->h_hostservs = hs;
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate 	for (i = 0, hn = he->h_aliases; i < hosts; i++) {
21977c478bd9Sstevel@tonic-gate 		sn = se ? se->s_aliases : NULL;
21987c478bd9Sstevel@tonic-gate 
21997c478bd9Sstevel@tonic-gate 		for (j = 0; j < servs; j++) {
22007c478bd9Sstevel@tonic-gate 			if (i == 0)
22017c478bd9Sstevel@tonic-gate 				hs->h_host = strdup(he->h_name);
22027c478bd9Sstevel@tonic-gate 			else
22037c478bd9Sstevel@tonic-gate 				hs->h_host = strdup(*hn);
22047c478bd9Sstevel@tonic-gate 			if (j == 0) {
22057c478bd9Sstevel@tonic-gate 				if (se)
22067c478bd9Sstevel@tonic-gate 					hs->h_serv = strdup(se->s_name);
22077c478bd9Sstevel@tonic-gate 				else {
22087c478bd9Sstevel@tonic-gate 					/* Convert to a number string */
22097c478bd9Sstevel@tonic-gate 					char stmp[16];
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate 					(void) sprintf(stmp, "%d", port);
22127c478bd9Sstevel@tonic-gate 					hs->h_serv = strdup(stmp);
22137c478bd9Sstevel@tonic-gate 				}
22147c478bd9Sstevel@tonic-gate 			} else
22157c478bd9Sstevel@tonic-gate 				hs->h_serv = strdup(*sn++);
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate 			if ((hs->h_host == 0) || (hs->h_serv == 0)) {
221861961e0fSrobinson 				free(result->h_hostservs);
221961961e0fSrobinson 				free(result);
22207c478bd9Sstevel@tonic-gate 				return (ND_NOMEM);
22217c478bd9Sstevel@tonic-gate 			}
22227c478bd9Sstevel@tonic-gate 			hs++;
22237c478bd9Sstevel@tonic-gate 		}
22247c478bd9Sstevel@tonic-gate 		if (i)
22257c478bd9Sstevel@tonic-gate 			hn++;
22267c478bd9Sstevel@tonic-gate 	}
22277c478bd9Sstevel@tonic-gate 	*(hslist) = result;
22287c478bd9Sstevel@tonic-gate 	return (ND_OK);
22297c478bd9Sstevel@tonic-gate }
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate /*
22327c478bd9Sstevel@tonic-gate  * Process results from nd_addrlist ( returned by netdir_getbyname)
22337c478bd9Sstevel@tonic-gate  * into a hostent using buf.
22347c478bd9Sstevel@tonic-gate  * *** ASSUMES that nd_addrlist->n_addrs->buf contains IP addresses in
22357c478bd9Sstevel@tonic-gate  * sockaddr_in's ***
22367c478bd9Sstevel@tonic-gate  */
22377c478bd9Sstevel@tonic-gate int
ndaddr2hent(int af,const char * nam,struct nd_addrlist * addrs,struct hostent * result,char * buffer,int buflen)22387c478bd9Sstevel@tonic-gate ndaddr2hent(int af, const char *nam, struct nd_addrlist *addrs,
22397c478bd9Sstevel@tonic-gate     struct hostent *result, char *buffer, int buflen)
22407c478bd9Sstevel@tonic-gate {
22417c478bd9Sstevel@tonic-gate 	int	i, count;
22427c478bd9Sstevel@tonic-gate 	struct	in_addr *addrp;
22437c478bd9Sstevel@tonic-gate 	struct	in6_addr *addr6p;
22447c478bd9Sstevel@tonic-gate 	char	**addrvec;
22457c478bd9Sstevel@tonic-gate 	struct	netbuf *na;
22467c478bd9Sstevel@tonic-gate 	size_t	len;
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 	result->h_name		= buffer;
22497c478bd9Sstevel@tonic-gate 	result->h_addrtype	= af;
22507c478bd9Sstevel@tonic-gate 	result->h_length	= (af == AF_INET) ? sizeof (*addrp):
22516392794bSMichen Chang 	    sizeof (*addr6p);
22527c478bd9Sstevel@tonic-gate 
22537c478bd9Sstevel@tonic-gate 	/*
22547c478bd9Sstevel@tonic-gate 	 * Build addrlist at start of buffer (after name);  store the
22557c478bd9Sstevel@tonic-gate 	 * addresses themselves at the end of the buffer.
22567c478bd9Sstevel@tonic-gate 	 */
22577c478bd9Sstevel@tonic-gate 	len = strlen(nam) + 1;
22587c478bd9Sstevel@tonic-gate 	addrvec = (char **)ROUND_UP(buffer + len, sizeof (*addrvec));
22597c478bd9Sstevel@tonic-gate 	result->h_addr_list 	= addrvec;
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate 	if (af == AF_INET) {
22627c478bd9Sstevel@tonic-gate 		addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen,
22637c478bd9Sstevel@tonic-gate 		    sizeof (*addrp));
22647c478bd9Sstevel@tonic-gate 
22657c478bd9Sstevel@tonic-gate 		count = addrs->n_cnt;
22667c478bd9Sstevel@tonic-gate 		if ((char *)(&addrvec[count + 1]) > (char *)(&addrp[-count]))
22677c478bd9Sstevel@tonic-gate 			return (ND_NOMEM);
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate 		(void) memcpy(buffer, nam, len);
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate 		for (na = addrs->n_addrs, i = 0;  i < count;  na++, i++) {
22727c478bd9Sstevel@tonic-gate 			--addrp;
22737c478bd9Sstevel@tonic-gate 			(void) memcpy(addrp,
227461961e0fSrobinson 			    /* LINTED pointer cast */
22757c478bd9Sstevel@tonic-gate 			    &((struct sockaddr_in *)na->buf)->sin_addr,
22767c478bd9Sstevel@tonic-gate 			    sizeof (*addrp));
22777c478bd9Sstevel@tonic-gate 			*addrvec++ = (char *)addrp;
22787c478bd9Sstevel@tonic-gate 		}
22797c478bd9Sstevel@tonic-gate 	} else {
22807c478bd9Sstevel@tonic-gate 		addr6p = (struct in6_addr *)ROUND_DOWN(buffer + buflen,
22816392794bSMichen Chang 		    sizeof (*addr6p));
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate 		count = addrs->n_cnt;
22847c478bd9Sstevel@tonic-gate 		if ((char *)(&addrvec[count + 1]) > (char *)(&addr6p[-count]))
22857c478bd9Sstevel@tonic-gate 			return (ND_NOMEM);
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 		(void) memcpy(buffer, nam, len);
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 		for (na = addrs->n_addrs, i = 0;  i < count;  na++, i++) {
22907c478bd9Sstevel@tonic-gate 			--addr6p;
22917c478bd9Sstevel@tonic-gate 			(void) memcpy(addr6p,
229261961e0fSrobinson 			    /* LINTED pointer cast */
22937c478bd9Sstevel@tonic-gate 			    &((struct sockaddr_in6 *)na->buf)->sin6_addr,
22947c478bd9Sstevel@tonic-gate 			    sizeof (*addr6p));
22957c478bd9Sstevel@tonic-gate 			*addrvec++ = (char *)addr6p;
22967c478bd9Sstevel@tonic-gate 		}
22977c478bd9Sstevel@tonic-gate 	}
22987c478bd9Sstevel@tonic-gate 	*addrvec = 0;
22997c478bd9Sstevel@tonic-gate 	result->h_aliases = addrvec;
23007c478bd9Sstevel@tonic-gate 
23017c478bd9Sstevel@tonic-gate 	return (ND_OK);
23027c478bd9Sstevel@tonic-gate }
23037c478bd9Sstevel@tonic-gate 
23047c478bd9Sstevel@tonic-gate /*
23057c478bd9Sstevel@tonic-gate  * Process results from nd_addrlist ( returned by netdir_getbyname)
23067c478bd9Sstevel@tonic-gate  * into a servent using buf.
23077c478bd9Sstevel@tonic-gate  */
23087c478bd9Sstevel@tonic-gate int
ndaddr2srent(const char * name,const char * proto,ushort_t port,struct servent * result,char * buffer,int buflen)23097c478bd9Sstevel@tonic-gate ndaddr2srent(const char *name, const char *proto, ushort_t port,
23107c478bd9Sstevel@tonic-gate     struct servent *result, char *buffer, int buflen)
23117c478bd9Sstevel@tonic-gate {
23127c478bd9Sstevel@tonic-gate 	size_t	i;
23137c478bd9Sstevel@tonic-gate 	char	*bufend = (buffer + buflen);
23147c478bd9Sstevel@tonic-gate 
23157c478bd9Sstevel@tonic-gate 	result->s_port = (int)port;
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate 	result->s_aliases =
23187c478bd9Sstevel@tonic-gate 	    (char **)ROUND_UP(buffer, sizeof (char *));
23197c478bd9Sstevel@tonic-gate 	result->s_aliases[0] = NULL;
23207c478bd9Sstevel@tonic-gate 	buffer = (char *)&result->s_aliases[1];
23217c478bd9Sstevel@tonic-gate 	result->s_name = buffer;
23227c478bd9Sstevel@tonic-gate 	i = strlen(name) + 1;
23237c478bd9Sstevel@tonic-gate 	if ((buffer + i) > bufend)
23247c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
23257c478bd9Sstevel@tonic-gate 	(void) memcpy(buffer, name, i);
23267c478bd9Sstevel@tonic-gate 	buffer += i;
23277c478bd9Sstevel@tonic-gate 
23287c478bd9Sstevel@tonic-gate 	result->s_proto	= buffer;
23297c478bd9Sstevel@tonic-gate 	i = strlen(proto) + 1;
23307c478bd9Sstevel@tonic-gate 	if ((buffer + i) > bufend)
23317c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
23327c478bd9Sstevel@tonic-gate 	(void) memcpy(buffer, proto, i);
23337c478bd9Sstevel@tonic-gate 	buffer += i;
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate 	return (ND_OK);
23367c478bd9Sstevel@tonic-gate }
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate /*
23397c478bd9Sstevel@tonic-gate  * Process results from nd_hostservlist ( returned by netdir_getbyaddr)
23407c478bd9Sstevel@tonic-gate  * into a hostent using buf.
23417c478bd9Sstevel@tonic-gate  * *** ASSUMES that nd_buf->buf is a sockaddr_in ***
23427c478bd9Sstevel@tonic-gate  */
23437c478bd9Sstevel@tonic-gate int
ndhostserv2hent(struct netbuf * nbuf,struct nd_hostservlist * addrs,struct hostent * result,char * buffer,int buflen)23447c478bd9Sstevel@tonic-gate ndhostserv2hent(struct netbuf *nbuf, struct nd_hostservlist *addrs,
23457c478bd9Sstevel@tonic-gate     struct hostent *result, char *buffer, int buflen)
23467c478bd9Sstevel@tonic-gate {
23477c478bd9Sstevel@tonic-gate 	int	i, count;
23487c478bd9Sstevel@tonic-gate 	char	*aliasp;
23497c478bd9Sstevel@tonic-gate 	char	**aliasvec;
23507c478bd9Sstevel@tonic-gate 	struct	sockaddr_in *sa;
23517c478bd9Sstevel@tonic-gate 	struct	nd_hostserv *hs;
23527c478bd9Sstevel@tonic-gate 	const	char *la;
23537c478bd9Sstevel@tonic-gate 	size_t	length;
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 	/* First, give the lonely address a specious home in h_addr_list. */
23567c478bd9Sstevel@tonic-gate 	aliasp   = (char  *)ROUND_UP(buffer, sizeof (sa->sin_addr));
235761961e0fSrobinson 	/* LINTED pointer cast */
23587c478bd9Sstevel@tonic-gate 	sa = (struct sockaddr_in *)nbuf->buf;
235961961e0fSrobinson 	(void) memcpy(aliasp, &(sa->sin_addr), sizeof (sa->sin_addr));
23607c478bd9Sstevel@tonic-gate 	aliasvec = (char **)ROUND_UP(aliasp + sizeof (sa->sin_addr),
23616392794bSMichen Chang 	    sizeof (*aliasvec));
23627c478bd9Sstevel@tonic-gate 	result->h_addr_list = aliasvec;
23637c478bd9Sstevel@tonic-gate 	*aliasvec++ = aliasp;
23647c478bd9Sstevel@tonic-gate 	*aliasvec++ = 0;
23657c478bd9Sstevel@tonic-gate 
23667c478bd9Sstevel@tonic-gate 	/*
23677c478bd9Sstevel@tonic-gate 	 * Build h_aliases at start of buffer (after addr and h_addr_list);
23687c478bd9Sstevel@tonic-gate 	 * store the alias strings at the end of the buffer (before h_name).
23697c478bd9Sstevel@tonic-gate 	 */
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 	aliasp = buffer + buflen;
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate 	result->h_aliases	= aliasvec;
23747c478bd9Sstevel@tonic-gate 
23757c478bd9Sstevel@tonic-gate 	hs = addrs->h_hostservs;
237661961e0fSrobinson 	if (!hs)
23777c478bd9Sstevel@tonic-gate 		return (ND_NOHOST);
23787c478bd9Sstevel@tonic-gate 
23797c478bd9Sstevel@tonic-gate 	length = strlen(hs->h_host) + 1;
23807c478bd9Sstevel@tonic-gate 	aliasp -= length;
23817c478bd9Sstevel@tonic-gate 	if ((char *)(&aliasvec[1]) > aliasp)
23827c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
23837c478bd9Sstevel@tonic-gate 	(void) memcpy(aliasp, hs->h_host, length);
23847c478bd9Sstevel@tonic-gate 
23857c478bd9Sstevel@tonic-gate 	result->h_name		= aliasp;
23867c478bd9Sstevel@tonic-gate 	result->h_addrtype	= AF_INET;
23877c478bd9Sstevel@tonic-gate 	result->h_length	= sizeof (sa->sin_addr);
23887c478bd9Sstevel@tonic-gate 
23897c478bd9Sstevel@tonic-gate 	/*
23907c478bd9Sstevel@tonic-gate 	 * Assumption: the netdir nametoaddr_libs
23917c478bd9Sstevel@tonic-gate 	 * sort the vector of (host, serv) pairs in such a way that
23927c478bd9Sstevel@tonic-gate 	 * all pairs with the same host name are contiguous.
23937c478bd9Sstevel@tonic-gate 	 */
23947c478bd9Sstevel@tonic-gate 	la = hs->h_host;
23957c478bd9Sstevel@tonic-gate 	count = addrs->h_cnt;
23967c478bd9Sstevel@tonic-gate 	for (i = 0;  i < count;  i++, hs++)
23977c478bd9Sstevel@tonic-gate 		if (strcmp(la, hs->h_host) != 0) {
23987c478bd9Sstevel@tonic-gate 			size_t len = strlen(hs->h_host) + 1;
23997c478bd9Sstevel@tonic-gate 
24007c478bd9Sstevel@tonic-gate 			aliasp -= len;
24017c478bd9Sstevel@tonic-gate 			if ((char *)(&aliasvec[2]) > aliasp)
24027c478bd9Sstevel@tonic-gate 				return (ND_NOMEM);
24037c478bd9Sstevel@tonic-gate 			(void) memcpy(aliasp, hs->h_host, len);
24047c478bd9Sstevel@tonic-gate 			*aliasvec++ = aliasp;
24057c478bd9Sstevel@tonic-gate 			la = hs->h_host;
24067c478bd9Sstevel@tonic-gate 		}
24077c478bd9Sstevel@tonic-gate 	*aliasvec = 0;
24087c478bd9Sstevel@tonic-gate 
24097c478bd9Sstevel@tonic-gate 	return (ND_OK);
24107c478bd9Sstevel@tonic-gate }
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate /*
24137c478bd9Sstevel@tonic-gate  * Process results from nd_hostservlist ( returned by netdir_getbyaddr)
24147c478bd9Sstevel@tonic-gate  * into a servent using buf.
24157c478bd9Sstevel@tonic-gate  */
24167c478bd9Sstevel@tonic-gate int
ndhostserv2srent(int port,const char * proto,struct nd_hostservlist * addrs,struct servent * result,char * buffer,int buflen)24177c478bd9Sstevel@tonic-gate ndhostserv2srent(int port, const char *proto, struct nd_hostservlist *addrs,
24187c478bd9Sstevel@tonic-gate     struct servent *result, char *buffer, int buflen)
24197c478bd9Sstevel@tonic-gate {
24207c478bd9Sstevel@tonic-gate 	int	i, count;
24217c478bd9Sstevel@tonic-gate 	char	*aliasp;
24227c478bd9Sstevel@tonic-gate 	char	**aliasvec;
24237c478bd9Sstevel@tonic-gate 	struct	nd_hostserv *hs;
24247c478bd9Sstevel@tonic-gate 	const	char *host_cname;
24257c478bd9Sstevel@tonic-gate 	size_t	leni, lenj;
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate 	result->s_port = port;
24287c478bd9Sstevel@tonic-gate 	/*
24297c478bd9Sstevel@tonic-gate 	 * Build s_aliases at start of buffer;
24307c478bd9Sstevel@tonic-gate 	 * store proto and aliases at the end of the buffer (before h_name).
24317c478bd9Sstevel@tonic-gate 	 */
24327c478bd9Sstevel@tonic-gate 
24337c478bd9Sstevel@tonic-gate 	aliasp = buffer + buflen;
24347c478bd9Sstevel@tonic-gate 	aliasvec = (char **)ROUND_UP(buffer, sizeof (char *));
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate 	result->s_aliases	= aliasvec;
24377c478bd9Sstevel@tonic-gate 
24387c478bd9Sstevel@tonic-gate 	hs = addrs->h_hostservs;
243961961e0fSrobinson 	if (!hs)
24407c478bd9Sstevel@tonic-gate 		return (ND_NOHOST);
24417c478bd9Sstevel@tonic-gate 	host_cname = hs->h_host;
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 	leni = strlen(proto) + 1;
24447c478bd9Sstevel@tonic-gate 	lenj = strlen(hs->h_serv) + 1;
24457c478bd9Sstevel@tonic-gate 	if ((char *)(&aliasvec[2]) > (aliasp - leni - lenj))
24467c478bd9Sstevel@tonic-gate 		return (ND_NOMEM);
24477c478bd9Sstevel@tonic-gate 
24487c478bd9Sstevel@tonic-gate 	aliasp -= leni;
24497c478bd9Sstevel@tonic-gate 	(void) memcpy(aliasp, proto, leni);
24507c478bd9Sstevel@tonic-gate 	result->s_proto = aliasp;
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 	aliasp -= lenj;
24537c478bd9Sstevel@tonic-gate 	(void) memcpy(aliasp, hs->h_serv, lenj);
24547c478bd9Sstevel@tonic-gate 	result->s_name = aliasp;
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	/*
24577c478bd9Sstevel@tonic-gate 	 * Assumption: the netdir nametoaddr_libs
24587c478bd9Sstevel@tonic-gate 	 * do a host aliases first and serv aliases next
24597c478bd9Sstevel@tonic-gate 	 * enumeration for creating the list of hostserv
24607c478bd9Sstevel@tonic-gate 	 * structures.
24617c478bd9Sstevel@tonic-gate 	 */
24627c478bd9Sstevel@tonic-gate 	count = addrs->h_cnt;
24637c478bd9Sstevel@tonic-gate 	for (i = 0;
24647c478bd9Sstevel@tonic-gate 	    i < count && hs->h_serv && strcmp(hs->h_host, host_cname) == 0;
24657c478bd9Sstevel@tonic-gate 	    i++, hs++) {
24667c478bd9Sstevel@tonic-gate 		size_t len = strlen(hs->h_serv) + 1;
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate 		aliasp -= len;
24697c478bd9Sstevel@tonic-gate 		if ((char *)(&aliasvec[2]) > aliasp)
24707c478bd9Sstevel@tonic-gate 			return (ND_NOMEM);
24717c478bd9Sstevel@tonic-gate 		(void) memcpy(aliasp, hs->h_serv, len);
24727c478bd9Sstevel@tonic-gate 		*aliasvec++ = aliasp;
24737c478bd9Sstevel@tonic-gate 	}
24747c478bd9Sstevel@tonic-gate 	*aliasvec = NULL;
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 	return (ND_OK);
24777c478bd9Sstevel@tonic-gate }
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate static int
nd2herrno(int nerr)24817c478bd9Sstevel@tonic-gate nd2herrno(int nerr)
24827c478bd9Sstevel@tonic-gate {
24837c478bd9Sstevel@tonic-gate 	switch (nerr) {
24847c478bd9Sstevel@tonic-gate 	case ND_OK:
24857c478bd9Sstevel@tonic-gate 		return (0);
24867c478bd9Sstevel@tonic-gate 	case ND_TRY_AGAIN:
24877c478bd9Sstevel@tonic-gate 		return (TRY_AGAIN);
24887c478bd9Sstevel@tonic-gate 	case ND_NO_RECOVERY:
24897c478bd9Sstevel@tonic-gate 	case ND_BADARG:
24907c478bd9Sstevel@tonic-gate 	case ND_NOMEM:
24917c478bd9Sstevel@tonic-gate 		return (NO_RECOVERY);
24927c478bd9Sstevel@tonic-gate 	case ND_NO_DATA:
24937c478bd9Sstevel@tonic-gate 		return (NO_DATA);
24947c478bd9Sstevel@tonic-gate 	case ND_NOHOST:
24957c478bd9Sstevel@tonic-gate 	case ND_NOSERV:
24967c478bd9Sstevel@tonic-gate 		return (HOST_NOT_FOUND);
24977c478bd9Sstevel@tonic-gate 	default:
24987c478bd9Sstevel@tonic-gate 		return (NO_RECOVERY);
24997c478bd9Sstevel@tonic-gate 	}
25007c478bd9Sstevel@tonic-gate }
25017c478bd9Sstevel@tonic-gate 
25027c478bd9Sstevel@tonic-gate /*
25037c478bd9Sstevel@tonic-gate  * This is a utility function so that various parts of libnsl can
25047c478bd9Sstevel@tonic-gate  * easily send ioctls down to ip.
25057c478bd9Sstevel@tonic-gate  *
25067c478bd9Sstevel@tonic-gate  */
25077c478bd9Sstevel@tonic-gate int
nss_ioctl(int af,int cmd,void * arg)25087c478bd9Sstevel@tonic-gate nss_ioctl(int af, int cmd, void *arg)
25097c478bd9Sstevel@tonic-gate {
25107c478bd9Sstevel@tonic-gate 	int	fd;
25117c478bd9Sstevel@tonic-gate 	char	*devpath;
25127c478bd9Sstevel@tonic-gate 	int	retv;
25137c478bd9Sstevel@tonic-gate 
25147c478bd9Sstevel@tonic-gate 	switch (af) {
25157c478bd9Sstevel@tonic-gate 	case AF_INET6:
25167c478bd9Sstevel@tonic-gate 		devpath = UDP6DEV;
25177c478bd9Sstevel@tonic-gate 		break;
25187c478bd9Sstevel@tonic-gate 	case AF_INET:
25197c478bd9Sstevel@tonic-gate 	case AF_UNSPEC:
25207c478bd9Sstevel@tonic-gate 	default:
25217c478bd9Sstevel@tonic-gate 		devpath = UDPDEV;
25227c478bd9Sstevel@tonic-gate 	}
25237c478bd9Sstevel@tonic-gate 	if ((fd = open(devpath, O_RDONLY)) < 0) {
25247c478bd9Sstevel@tonic-gate 		return (-1);
25257c478bd9Sstevel@tonic-gate 	}
25267c478bd9Sstevel@tonic-gate 	while ((retv = ioctl(fd, cmd, arg)) == -1) {
25277c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
25287c478bd9Sstevel@tonic-gate 	break;
25297c478bd9Sstevel@tonic-gate 	}
253061961e0fSrobinson 	(void) close(fd);
25317c478bd9Sstevel@tonic-gate 	return (retv);
25327c478bd9Sstevel@tonic-gate }
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate static int
nss_strioctl(int af,int cmd,void * ptr,int ilen)25357c478bd9Sstevel@tonic-gate nss_strioctl(int af, int cmd, void *ptr, int ilen)
25367c478bd9Sstevel@tonic-gate {
25377c478bd9Sstevel@tonic-gate 	struct strioctl str;
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate 	str.ic_cmd = cmd;
25407c478bd9Sstevel@tonic-gate 	str.ic_timout = 0;
25417c478bd9Sstevel@tonic-gate 	str.ic_len = ilen;
25427c478bd9Sstevel@tonic-gate 	str.ic_dp = ptr;
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 	return (nss_ioctl(af, I_STR, &str));
25457c478bd9Sstevel@tonic-gate }
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate static struct ifinfo *
get_local_info(void)25487c478bd9Sstevel@tonic-gate get_local_info(void)
25497c478bd9Sstevel@tonic-gate {
25507c478bd9Sstevel@tonic-gate 	int	numifs;
25517c478bd9Sstevel@tonic-gate 	int	n;
25527c478bd9Sstevel@tonic-gate 	char	*buf = NULL;
25537c478bd9Sstevel@tonic-gate 	size_t	needed;
25547c478bd9Sstevel@tonic-gate 	struct lifconf	lifc;
25557c478bd9Sstevel@tonic-gate 	struct lifreq	lifreq, *lifr;
25567c478bd9Sstevel@tonic-gate 	struct lifnum	lifn;
25577c478bd9Sstevel@tonic-gate 	struct ifinfo	*localinfo;
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate 	lifn.lifn_family = AF_UNSPEC;
25607c478bd9Sstevel@tonic-gate 	lifn.lifn_flags = 0;
25617c478bd9Sstevel@tonic-gate 
25627c478bd9Sstevel@tonic-gate getifnum:
25637c478bd9Sstevel@tonic-gate 	if (nss_ioctl(AF_UNSPEC, SIOCGLIFNUM, &lifn) == -1) {
25647c478bd9Sstevel@tonic-gate 		numifs = MAXIFS;
25657c478bd9Sstevel@tonic-gate 	} else {
25667c478bd9Sstevel@tonic-gate 		numifs = lifn.lifn_count;
25677c478bd9Sstevel@tonic-gate 	}
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate 	/*
25707c478bd9Sstevel@tonic-gate 	 * Add a small fudge factor in case interfaces get plumbed between
25717c478bd9Sstevel@tonic-gate 	 * the call to SIOCGLIFNUM and SIOCGLIFCONF.
25727c478bd9Sstevel@tonic-gate 	 */
25737c478bd9Sstevel@tonic-gate 	needed = (numifs + 4) * sizeof (lifreq);
25747c478bd9Sstevel@tonic-gate 	if (buf == NULL)
25757c478bd9Sstevel@tonic-gate 		buf = malloc(needed);
25767c478bd9Sstevel@tonic-gate 	else
25777c478bd9Sstevel@tonic-gate 		buf = realloc(buf, needed);
25787c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
25797c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m");
25807c478bd9Sstevel@tonic-gate 		_nderror = ND_NOMEM;
25817c478bd9Sstevel@tonic-gate 		return (NULL);
25827c478bd9Sstevel@tonic-gate 	}
25837c478bd9Sstevel@tonic-gate 	lifc.lifc_family = AF_UNSPEC;
25847c478bd9Sstevel@tonic-gate 	lifc.lifc_flags = 0;
25857c478bd9Sstevel@tonic-gate 	lifc.lifc_len = needed;
25867c478bd9Sstevel@tonic-gate 	lifc.lifc_buf = buf;
25877c478bd9Sstevel@tonic-gate 	if (nss_ioctl(AF_UNSPEC, SIOCGLIFCONF, &lifc) == -1) {
25887c478bd9Sstevel@tonic-gate 		/*
25897c478bd9Sstevel@tonic-gate 		 * IP returns EINVAL if the buffer was too small to fit
25907c478bd9Sstevel@tonic-gate 		 * all of the entries.  If that's the case, go back and
25917c478bd9Sstevel@tonic-gate 		 * try again.
25927c478bd9Sstevel@tonic-gate 		 */
25937c478bd9Sstevel@tonic-gate 		if (errno == EINVAL)
25947c478bd9Sstevel@tonic-gate 			goto getifnum;
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "n2a get_local_info: "
25977c478bd9Sstevel@tonic-gate 		    "ioctl (get interface configuration): %m");
25987c478bd9Sstevel@tonic-gate 		free(buf);
25997c478bd9Sstevel@tonic-gate 		_nderror = ND_SYSTEM;
26007c478bd9Sstevel@tonic-gate 		return (NULL);
26017c478bd9Sstevel@tonic-gate 	}
260261961e0fSrobinson 	/* LINTED pointer cast */
26037c478bd9Sstevel@tonic-gate 	lifr = (struct lifreq *)buf;
26047c478bd9Sstevel@tonic-gate 	numifs = lifc.lifc_len/sizeof (lifreq);
260561961e0fSrobinson 	localinfo = malloc(ifinfosize(numifs));
26067c478bd9Sstevel@tonic-gate 	if (localinfo == NULL) {
26077c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "n2a get_local_info: malloc failed: %m");
26087c478bd9Sstevel@tonic-gate 		free(buf);
26097c478bd9Sstevel@tonic-gate 		_nderror = ND_SYSTEM;
26107c478bd9Sstevel@tonic-gate 		return (NULL);
26117c478bd9Sstevel@tonic-gate 	}
26127c478bd9Sstevel@tonic-gate 
261361961e0fSrobinson 	/* LINTED pointer cast */
26147c478bd9Sstevel@tonic-gate 	localinfo->addresses = (struct __ifaddr *)
26157c478bd9Sstevel@tonic-gate 	    ((char *)localinfo + sizeof (struct ifinfo));
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 	for (localinfo->count = 0, n = numifs; n > 0; n--, lifr++) {
26187c478bd9Sstevel@tonic-gate 		int af;
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate 		lifreq = *lifr;
26217c478bd9Sstevel@tonic-gate 		af = lifreq.lifr_addr.ss_family;
26227c478bd9Sstevel@tonic-gate 
26237c478bd9Sstevel@tonic-gate 		/* Squirrel away the address */
26247c478bd9Sstevel@tonic-gate 		if (ifassign(lifreq, localinfo->count, IF_ADDR) == 0)
26257c478bd9Sstevel@tonic-gate 			continue;
26267c478bd9Sstevel@tonic-gate 
26277c478bd9Sstevel@tonic-gate 		if (nss_ioctl(af, SIOCGLIFFLAGS, &lifreq) < 0) {
26287c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
26297c478bd9Sstevel@tonic-gate 			    "n2a get_local_info: "
26307c478bd9Sstevel@tonic-gate 			    "ioctl (get interface flags): %m");
26317c478bd9Sstevel@tonic-gate 			continue;
26327c478bd9Sstevel@tonic-gate 		}
26337c478bd9Sstevel@tonic-gate 		if (!(lifreq.lifr_flags & IFF_UP))
26347c478bd9Sstevel@tonic-gate 			continue;
26357c478bd9Sstevel@tonic-gate 
26367c478bd9Sstevel@tonic-gate 		if (nss_ioctl(af, SIOCGLIFNETMASK, &lifreq) < 0) {
26377c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
26387c478bd9Sstevel@tonic-gate 			    "n2a get_local_info: "
26397c478bd9Sstevel@tonic-gate 			    "ioctl (get interface netmask): %m");
26407c478bd9Sstevel@tonic-gate 			continue;
26417c478bd9Sstevel@tonic-gate 		}
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate 		if (ifassign(lifreq, localinfo->count, IF_MASK) == 0)
26447c478bd9Sstevel@tonic-gate 			continue;
26457c478bd9Sstevel@tonic-gate 
26467c478bd9Sstevel@tonic-gate 		localinfo->count++;
26477c478bd9Sstevel@tonic-gate 	}
26487c478bd9Sstevel@tonic-gate 
26497c478bd9Sstevel@tonic-gate 	free(buf);
26507c478bd9Sstevel@tonic-gate 	return (localinfo);
26517c478bd9Sstevel@tonic-gate }
26527c478bd9Sstevel@tonic-gate 
26537c478bd9Sstevel@tonic-gate static int
__inet_ifassign(sa_family_t af,struct __ifaddr * ifa,__ifaddr_type type,void * addr)26547c478bd9Sstevel@tonic-gate __inet_ifassign(sa_family_t af, struct __ifaddr *ifa, __ifaddr_type type,
26557c478bd9Sstevel@tonic-gate     void *addr) {
26567c478bd9Sstevel@tonic-gate 	switch (type) {
26577c478bd9Sstevel@tonic-gate 	case IF_ADDR:
26587c478bd9Sstevel@tonic-gate 		ifa->af = af;
26597c478bd9Sstevel@tonic-gate 		if (af == AF_INET6) {
26607c478bd9Sstevel@tonic-gate 			ifa->addr.in6 = *(struct in6_addr *)addr;
26617c478bd9Sstevel@tonic-gate 		} else {
26627c478bd9Sstevel@tonic-gate 			ifa->addr.in4 = *(struct in_addr *)addr;
26637c478bd9Sstevel@tonic-gate 		}
26647c478bd9Sstevel@tonic-gate 		break;
26657c478bd9Sstevel@tonic-gate 	case IF_MASK:
26667c478bd9Sstevel@tonic-gate 		if (ifa->af == af) {
26677c478bd9Sstevel@tonic-gate 			if (af == AF_INET6) {
26687c478bd9Sstevel@tonic-gate 				ifa->mask.in6 = *(struct in6_addr *)addr;
26697c478bd9Sstevel@tonic-gate 			} else {
26707c478bd9Sstevel@tonic-gate 				ifa->mask.in4 = *(struct in_addr *)addr;
26717c478bd9Sstevel@tonic-gate 			}
26727c478bd9Sstevel@tonic-gate 		} else {
26737c478bd9Sstevel@tonic-gate 			return (0);
26747c478bd9Sstevel@tonic-gate 		}
26757c478bd9Sstevel@tonic-gate 		break;
26767c478bd9Sstevel@tonic-gate 	default:
26777c478bd9Sstevel@tonic-gate 		return (0);
26787c478bd9Sstevel@tonic-gate 	}
26797c478bd9Sstevel@tonic-gate 
26807c478bd9Sstevel@tonic-gate 	return (1);
26817c478bd9Sstevel@tonic-gate }
26827c478bd9Sstevel@tonic-gate 
26837c478bd9Sstevel@tonic-gate /*
26847c478bd9Sstevel@tonic-gate  *  Some higher-level routines for determining if an address is
26857c478bd9Sstevel@tonic-gate  *  on a local network.
26867c478bd9Sstevel@tonic-gate  *
26877c478bd9Sstevel@tonic-gate  *      __inet_get_local_interfaces() - get an opaque handle with
26887c478bd9Sstevel@tonic-gate  *          with a list of local interfaces
26897c478bd9Sstevel@tonic-gate  *      __inet_address_is_local() - return 1 if an address is
26907c478bd9Sstevel@tonic-gate  *          on a local network; 0 otherwise
26917c478bd9Sstevel@tonic-gate  *      __inet_free_local_interfaces() - free handle that was
26927c478bd9Sstevel@tonic-gate  *          returned by __inet_get_local_interfaces()
26937c478bd9Sstevel@tonic-gate  *
26947c478bd9Sstevel@tonic-gate  *  A typical calling sequence is:
26957c478bd9Sstevel@tonic-gate  *
26967c478bd9Sstevel@tonic-gate  *      p = __inet_get_local_interfaces();
26977c478bd9Sstevel@tonic-gate  *      if (__inet_address_is_local(p, inaddr)) {
26987c478bd9Sstevel@tonic-gate  *          ...
26997c478bd9Sstevel@tonic-gate  *      }
27007c478bd9Sstevel@tonic-gate  *      __inet_free_local_interfaces(p);
27017c478bd9Sstevel@tonic-gate  */
27027c478bd9Sstevel@tonic-gate 
27037c478bd9Sstevel@tonic-gate /*
27047c478bd9Sstevel@tonic-gate  *  Return an opaque pointer to a list of configured interfaces.
27057c478bd9Sstevel@tonic-gate  */
27067c478bd9Sstevel@tonic-gate void *
__inet_get_local_interfaces(void)27077c478bd9Sstevel@tonic-gate __inet_get_local_interfaces(void)
27087c478bd9Sstevel@tonic-gate {
27097c478bd9Sstevel@tonic-gate 	return (get_local_info());
27107c478bd9Sstevel@tonic-gate }
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate /*
27137c478bd9Sstevel@tonic-gate  *  Free memory allocated by inet_local_interfaces().
27147c478bd9Sstevel@tonic-gate  */
27157c478bd9Sstevel@tonic-gate void
__inet_free_local_interfaces(void * p)27167c478bd9Sstevel@tonic-gate __inet_free_local_interfaces(void *p)
27177c478bd9Sstevel@tonic-gate {
27187c478bd9Sstevel@tonic-gate 	free(p);
27197c478bd9Sstevel@tonic-gate }
27207c478bd9Sstevel@tonic-gate 
27217c478bd9Sstevel@tonic-gate /*
27227c478bd9Sstevel@tonic-gate  *  Determine if an address is on a local network.
27237c478bd9Sstevel@tonic-gate  *
27247c478bd9Sstevel@tonic-gate  *  Might have made sense to use SIOCTONLINK, except that it doesn't
27257c478bd9Sstevel@tonic-gate  *  handle matching on IPv4 network addresses.
27267c478bd9Sstevel@tonic-gate  */
27277c478bd9Sstevel@tonic-gate int
__inet_address_is_local_af(void * p,sa_family_t af,void * addr)27287c478bd9Sstevel@tonic-gate __inet_address_is_local_af(void *p, sa_family_t af, void *addr) {
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate 	struct ifinfo	*localinfo = (struct ifinfo *)p;
27317c478bd9Sstevel@tonic-gate 	int		i, a;
27327c478bd9Sstevel@tonic-gate 	struct in_addr	v4addr;
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate 	if (localinfo == 0)
27357c478bd9Sstevel@tonic-gate 		return (0);
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate 	if (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr)) {
27387c478bd9Sstevel@tonic-gate 		IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addr, &v4addr);
27397c478bd9Sstevel@tonic-gate 		af = AF_INET;
27407c478bd9Sstevel@tonic-gate 		addr = (void *)&v4addr;
27417c478bd9Sstevel@tonic-gate 	}
27427c478bd9Sstevel@tonic-gate 
27437c478bd9Sstevel@tonic-gate 	for (i = 0; i < localinfo->count; i++) {
27447c478bd9Sstevel@tonic-gate 		if (ifaf(i) == af) {
27457c478bd9Sstevel@tonic-gate 			if (af == AF_INET6) {
27467c478bd9Sstevel@tonic-gate 				struct in6_addr *a6 = (struct in6_addr *)addr;
27477c478bd9Sstevel@tonic-gate 				for (a = 0; a < sizeof (a6->s6_addr); a++) {
27487c478bd9Sstevel@tonic-gate 					if ((a6->s6_addr[a] &
27497c478bd9Sstevel@tonic-gate 						ifmask6(i).s6_addr[a]) !=
27507c478bd9Sstevel@tonic-gate 						(ifaddr6(i).s6_addr[a] &
27517c478bd9Sstevel@tonic-gate 						ifmask6(i).s6_addr[a]))
27527c478bd9Sstevel@tonic-gate 						break;
27537c478bd9Sstevel@tonic-gate 				}
27547c478bd9Sstevel@tonic-gate 				if (a >= sizeof (a6->s6_addr))
27557c478bd9Sstevel@tonic-gate 					return (1);
27567c478bd9Sstevel@tonic-gate 			} else {
27577c478bd9Sstevel@tonic-gate 				if ((((struct in_addr *)addr)->s_addr &
27587c478bd9Sstevel@tonic-gate 						ifmask4(i).s_addr) ==
27597c478bd9Sstevel@tonic-gate 					(ifaddr4(i).s_addr &
27607c478bd9Sstevel@tonic-gate 						ifmask4(i).s_addr))
27617c478bd9Sstevel@tonic-gate 					return (1);
27627c478bd9Sstevel@tonic-gate 			}
27637c478bd9Sstevel@tonic-gate 		}
27647c478bd9Sstevel@tonic-gate 	}
27657c478bd9Sstevel@tonic-gate 
27667c478bd9Sstevel@tonic-gate 	return (0);
27677c478bd9Sstevel@tonic-gate }
27687c478bd9Sstevel@tonic-gate 
27697c478bd9Sstevel@tonic-gate int
__inet_address_is_local(void * p,struct in_addr addr)27707c478bd9Sstevel@tonic-gate __inet_address_is_local(void *p, struct in_addr addr)
27717c478bd9Sstevel@tonic-gate {
27727c478bd9Sstevel@tonic-gate 	return (__inet_address_is_local_af(p, AF_INET, &addr));
27737c478bd9Sstevel@tonic-gate }
27747c478bd9Sstevel@tonic-gate 
27757c478bd9Sstevel@tonic-gate int
__inet_uaddr_is_local(void * p,struct netconfig * nc,char * uaddr)27767c478bd9Sstevel@tonic-gate __inet_uaddr_is_local(void *p, struct netconfig *nc, char *uaddr)
27777c478bd9Sstevel@tonic-gate {
27787c478bd9Sstevel@tonic-gate 	struct netbuf		*taddr;
27797c478bd9Sstevel@tonic-gate 	sa_family_t		af;
27807c478bd9Sstevel@tonic-gate 	int			ret;
27817c478bd9Sstevel@tonic-gate 
27827c478bd9Sstevel@tonic-gate 	taddr = uaddr2taddr(nc, uaddr);
27837c478bd9Sstevel@tonic-gate 	if (taddr == 0)
27847c478bd9Sstevel@tonic-gate 		return (0);
27857c478bd9Sstevel@tonic-gate 
278661961e0fSrobinson 	/* LINTED pointer cast */
27877c478bd9Sstevel@tonic-gate 	af = ((struct sockaddr *)taddr->buf)->sa_family;
27887c478bd9Sstevel@tonic-gate 
27896392794bSMichen Chang 	ret = __inet_address_is_local_af(p, af, (af == AF_INET6) ?
27906392794bSMichen Chang 	    /* LINTED pointer cast */
27916392794bSMichen Chang 	    (void *)&((struct sockaddr_in6 *)taddr->buf)->sin6_addr :
27926392794bSMichen Chang 	    /* LINTED pointer cast */
27936392794bSMichen Chang 	    (void *)&((struct sockaddr_in *)taddr->buf)->sin_addr);
27947c478bd9Sstevel@tonic-gate 
27957c478bd9Sstevel@tonic-gate 	netdir_free(taddr, ND_ADDR);
27967c478bd9Sstevel@tonic-gate 	return (ret);
27977c478bd9Sstevel@tonic-gate }
27987c478bd9Sstevel@tonic-gate 
27997c478bd9Sstevel@tonic-gate 
28007c478bd9Sstevel@tonic-gate int
__inet_address_count(void * p)28017c478bd9Sstevel@tonic-gate __inet_address_count(void *p)
28027c478bd9Sstevel@tonic-gate {
28037c478bd9Sstevel@tonic-gate 	struct ifinfo *lp = (struct ifinfo *)p;
28047c478bd9Sstevel@tonic-gate 
28057c478bd9Sstevel@tonic-gate 	if (lp != 0) {
28067c478bd9Sstevel@tonic-gate 		return (lp->count);
28077c478bd9Sstevel@tonic-gate 	} else {
28087c478bd9Sstevel@tonic-gate 		return (0);
28097c478bd9Sstevel@tonic-gate 	}
28107c478bd9Sstevel@tonic-gate }
28117c478bd9Sstevel@tonic-gate 
28127c478bd9Sstevel@tonic-gate uint32_t
__inet_get_addr(void * p,int n)28137c478bd9Sstevel@tonic-gate __inet_get_addr(void *p, int n)
28147c478bd9Sstevel@tonic-gate {
28157c478bd9Sstevel@tonic-gate 	struct ifinfo *localinfo = (struct ifinfo *)p;
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 	if (localinfo == 0 || n >= localinfo->count || ifaf(n) != AF_INET)
28187c478bd9Sstevel@tonic-gate 		return (0);
28197c478bd9Sstevel@tonic-gate 
28207c478bd9Sstevel@tonic-gate 	return (ifaddr4(n).s_addr);
28217c478bd9Sstevel@tonic-gate }
28227c478bd9Sstevel@tonic-gate 
28237c478bd9Sstevel@tonic-gate uint32_t
__inet_get_network(void * p,int n)28247c478bd9Sstevel@tonic-gate __inet_get_network(void *p, int n)
28257c478bd9Sstevel@tonic-gate {
28267c478bd9Sstevel@tonic-gate 	struct ifinfo *localinfo = (struct ifinfo *)p;
28277c478bd9Sstevel@tonic-gate 
28287c478bd9Sstevel@tonic-gate 	if (localinfo == 0 || n >= localinfo->count || ifaf(n) != AF_INET)
28297c478bd9Sstevel@tonic-gate 		return (0);
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate 	return (ifaddr4(n).s_addr & ifmask4(n).s_addr);
28327c478bd9Sstevel@tonic-gate }
28337c478bd9Sstevel@tonic-gate 
28347c478bd9Sstevel@tonic-gate char *
__inet_get_uaddr(void * p,struct netconfig * nc,int n)28357c478bd9Sstevel@tonic-gate __inet_get_uaddr(void *p, struct netconfig *nc, int n)
28367c478bd9Sstevel@tonic-gate {
28377c478bd9Sstevel@tonic-gate 	struct ifinfo *localinfo = (struct ifinfo *)p;
28387c478bd9Sstevel@tonic-gate 	char *uaddr;
28397c478bd9Sstevel@tonic-gate 	struct sockaddr_in sin4;
28407c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 sin6;
28417c478bd9Sstevel@tonic-gate 	struct netbuf nb;
28427c478bd9Sstevel@tonic-gate 
28437c478bd9Sstevel@tonic-gate 	if (localinfo == 0 || nc == 0 || n >= localinfo->count)
28447c478bd9Sstevel@tonic-gate 		return (0);
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 	if (ifaf(n) == AF_INET6) {
28477c478bd9Sstevel@tonic-gate 		if (strcmp(NC_INET6, nc->nc_protofmly) != 0)
28487c478bd9Sstevel@tonic-gate 			return (0);
284961961e0fSrobinson 		(void) memset(&sin6, 0, sizeof (sin6));
28507c478bd9Sstevel@tonic-gate 		sin6.sin6_family = AF_INET6;
28517c478bd9Sstevel@tonic-gate 		sin6.sin6_addr = ifaddr6(n);
28527c478bd9Sstevel@tonic-gate 		nb.buf = (char *)&sin6;
28537c478bd9Sstevel@tonic-gate 		nb.len = sizeof (sin6);
28547c478bd9Sstevel@tonic-gate 	} else {
28557c478bd9Sstevel@tonic-gate 		if (strcmp(NC_INET, nc->nc_protofmly) != 0)
28567c478bd9Sstevel@tonic-gate 			return (0);
285761961e0fSrobinson 		(void) memset(&sin4, 0, sizeof (sin4));
28587c478bd9Sstevel@tonic-gate 		sin4.sin_family = AF_INET;
28597c478bd9Sstevel@tonic-gate 		sin4.sin_addr = ifaddr4(n);
28607c478bd9Sstevel@tonic-gate 		nb.buf = (char *)&sin4;
28617c478bd9Sstevel@tonic-gate 		nb.len = sizeof (sin4);
28627c478bd9Sstevel@tonic-gate 	}
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate 	nb.maxlen = nb.len;
28657c478bd9Sstevel@tonic-gate 
28667c478bd9Sstevel@tonic-gate 	uaddr = taddr2uaddr(nc, &nb);
28677c478bd9Sstevel@tonic-gate 	return (uaddr);
28687c478bd9Sstevel@tonic-gate }
28697c478bd9Sstevel@tonic-gate 
28707c478bd9Sstevel@tonic-gate char *
__inet_get_networka(void * p,int n)28717c478bd9Sstevel@tonic-gate __inet_get_networka(void *p, int n)
28727c478bd9Sstevel@tonic-gate {
28737c478bd9Sstevel@tonic-gate 	struct ifinfo	*localinfo = (struct ifinfo *)p;
28747c478bd9Sstevel@tonic-gate 
28757c478bd9Sstevel@tonic-gate 	if (localinfo == 0 || n >= localinfo->count)
28767c478bd9Sstevel@tonic-gate 		return (0);
28777c478bd9Sstevel@tonic-gate 
28787c478bd9Sstevel@tonic-gate 	if (ifaf(n) == AF_INET6) {
28797c478bd9Sstevel@tonic-gate 		char		buf[INET6_ADDRSTRLEN];
28807c478bd9Sstevel@tonic-gate 		struct in6_addr	in6;
28817c478bd9Sstevel@tonic-gate 		int		i;
28827c478bd9Sstevel@tonic-gate 
28837c478bd9Sstevel@tonic-gate 		for (i = 0; i < sizeof (in6.s6_addr); i++) {
28847c478bd9Sstevel@tonic-gate 			in6.s6_addr[i] = ifaddr6(n).s6_addr[i] &
28856392794bSMichen Chang 			    ifmask6(n).s6_addr[i];
28867c478bd9Sstevel@tonic-gate 		}
28877c478bd9Sstevel@tonic-gate 		return (strdup(inet_ntop(AF_INET6, &in6, buf, sizeof (buf))));
28887c478bd9Sstevel@tonic-gate 	} else {
28897c478bd9Sstevel@tonic-gate 		struct in_addr	in4;
28907c478bd9Sstevel@tonic-gate 
28917c478bd9Sstevel@tonic-gate 		in4.s_addr = ifaddr4(n).s_addr & ifmask4(n).s_addr;
28927c478bd9Sstevel@tonic-gate 		return (strdup(inet_ntoa(in4)));
28937c478bd9Sstevel@tonic-gate 	}
28947c478bd9Sstevel@tonic-gate }
28957c478bd9Sstevel@tonic-gate 
28967c478bd9Sstevel@tonic-gate static int
in_list(struct in_addr * addrs,int n,struct in_addr a)28977c478bd9Sstevel@tonic-gate in_list(struct in_addr *addrs, int n, struct in_addr a)
28987c478bd9Sstevel@tonic-gate {
28997c478bd9Sstevel@tonic-gate 	int i;
29007c478bd9Sstevel@tonic-gate 
29017c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
29027c478bd9Sstevel@tonic-gate 		if (addrs[i].s_addr == a.s_addr)
29037c478bd9Sstevel@tonic-gate 			return (1);
29047c478bd9Sstevel@tonic-gate 	}
29057c478bd9Sstevel@tonic-gate 	return (0);
29067c478bd9Sstevel@tonic-gate }
29077c478bd9Sstevel@tonic-gate 
29087c478bd9Sstevel@tonic-gate static int
getbroadcastnets(struct netconfig * tp,struct in_addr ** addrs)29097c478bd9Sstevel@tonic-gate getbroadcastnets(struct netconfig *tp, struct in_addr **addrs)
29107c478bd9Sstevel@tonic-gate {
29117c478bd9Sstevel@tonic-gate 	struct ifconf ifc;
29127c478bd9Sstevel@tonic-gate 	struct ifreq ifreq, *ifr;
29137c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
29147c478bd9Sstevel@tonic-gate 	struct in_addr a;
29157c478bd9Sstevel@tonic-gate 	int fd;
29167c478bd9Sstevel@tonic-gate 	int n, i, numifs;
29177c478bd9Sstevel@tonic-gate 	char *buf;
29187c478bd9Sstevel@tonic-gate 	int	use_loopback = 0;
29197c478bd9Sstevel@tonic-gate 
29207c478bd9Sstevel@tonic-gate 	_nderror = ND_SYSTEM;
29217c478bd9Sstevel@tonic-gate 	fd = open(tp->nc_device, O_RDONLY);
29227c478bd9Sstevel@tonic-gate 	if (fd < 0) {
29237c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
29247c478bd9Sstevel@tonic-gate 	    "broadcast: open to get interface configuration: %m");
29257c478bd9Sstevel@tonic-gate 		return (0);
29267c478bd9Sstevel@tonic-gate 	}
29277c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0)
29287c478bd9Sstevel@tonic-gate 		numifs = MAXIFS;
292961961e0fSrobinson 	buf = malloc(numifs * sizeof (struct ifreq));
29307c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
29317c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "broadcast: malloc failed: %m");
29327c478bd9Sstevel@tonic-gate 		(void) close(fd);
29337c478bd9Sstevel@tonic-gate 		return (0);
29347c478bd9Sstevel@tonic-gate 	}
293561961e0fSrobinson 	*addrs = malloc(numifs * sizeof (struct in_addr));
29367c478bd9Sstevel@tonic-gate 	if (*addrs == NULL) {
29377c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "broadcast: malloc failed: %m");
29387c478bd9Sstevel@tonic-gate 		free(buf);
29397c478bd9Sstevel@tonic-gate 		(void) close(fd);
29407c478bd9Sstevel@tonic-gate 		return (0);
29417c478bd9Sstevel@tonic-gate 	}
29427c478bd9Sstevel@tonic-gate 	ifc.ifc_len = numifs * (int)sizeof (struct ifreq);
29437c478bd9Sstevel@tonic-gate 	ifc.ifc_buf = buf;
29447c478bd9Sstevel@tonic-gate 	/*
29457c478bd9Sstevel@tonic-gate 	 * Ideally, this ioctl should also tell me, how many bytes were
29467c478bd9Sstevel@tonic-gate 	 * finally allocated, but it doesnt.
29477c478bd9Sstevel@tonic-gate 	 */
29487c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) {
29497c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
29507c478bd9Sstevel@tonic-gate 	    "broadcast: ioctl (get interface configuration): %m");
29517c478bd9Sstevel@tonic-gate 		free(buf);
29527c478bd9Sstevel@tonic-gate 		free(*addrs);
29537c478bd9Sstevel@tonic-gate 		(void) close(fd);
29547c478bd9Sstevel@tonic-gate 		return (0);
29557c478bd9Sstevel@tonic-gate 	}
29567c478bd9Sstevel@tonic-gate 
29577c478bd9Sstevel@tonic-gate retry:
295861961e0fSrobinson 	/* LINTED pointer cast */
29597c478bd9Sstevel@tonic-gate 	ifr = (struct ifreq *)buf;
29607c478bd9Sstevel@tonic-gate 	for (i = 0, n = ifc.ifc_len / (int)sizeof (struct ifreq);
29616392794bSMichen Chang 	    n > 0; n--, ifr++) {
29627c478bd9Sstevel@tonic-gate 		ifreq = *ifr;
29637c478bd9Sstevel@tonic-gate 		if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
29646392794bSMichen Chang 			(void) syslog(LOG_ERR, "broadcast: "
29656392794bSMichen Chang 			    "ioctl (get interface flags): %m");
29667c478bd9Sstevel@tonic-gate 			continue;
29677c478bd9Sstevel@tonic-gate 		}
29687c478bd9Sstevel@tonic-gate 		if (!(ifreq.ifr_flags & IFF_UP) ||
29697c478bd9Sstevel@tonic-gate 		    (ifr->ifr_addr.sa_family != AF_INET))
29707c478bd9Sstevel@tonic-gate 			continue;
29717c478bd9Sstevel@tonic-gate 		if (ifreq.ifr_flags & IFF_BROADCAST) {
297261961e0fSrobinson 			/* LINTED pointer cast */
29737c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&ifr->ifr_addr;
29747c478bd9Sstevel@tonic-gate 			if (ioctl(fd, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
29757c478bd9Sstevel@tonic-gate 				/* May not work with other implementation */
29767c478bd9Sstevel@tonic-gate 				a = _inet_makeaddr(
29777c478bd9Sstevel@tonic-gate 				    inet_netof(sin->sin_addr),
29787c478bd9Sstevel@tonic-gate 				    INADDR_ANY);
29797c478bd9Sstevel@tonic-gate 				if (!in_list(*addrs, i, a))
29807c478bd9Sstevel@tonic-gate 					(*addrs)[i++] = a;
29817c478bd9Sstevel@tonic-gate 			} else {
298261961e0fSrobinson 				/* LINTED pointer cast */
29837c478bd9Sstevel@tonic-gate 				a = ((struct sockaddr_in *)
29847c478bd9Sstevel@tonic-gate 				    &ifreq.ifr_addr)->sin_addr;
29857c478bd9Sstevel@tonic-gate 				if (!in_list(*addrs, i, a))
29867c478bd9Sstevel@tonic-gate 					(*addrs)[i++] = a;
29877c478bd9Sstevel@tonic-gate 			}
29887c478bd9Sstevel@tonic-gate 			continue;
29897c478bd9Sstevel@tonic-gate 		}
29907c478bd9Sstevel@tonic-gate 		if (use_loopback && (ifreq.ifr_flags & IFF_LOOPBACK)) {
299161961e0fSrobinson 			/* LINTED pointer cast */
29927c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&ifr->ifr_addr;
29937c478bd9Sstevel@tonic-gate 			a = sin->sin_addr;
29947c478bd9Sstevel@tonic-gate 			if (!in_list(*addrs, i, a))
29957c478bd9Sstevel@tonic-gate 				(*addrs)[i++] = a;
29967c478bd9Sstevel@tonic-gate 			continue;
29977c478bd9Sstevel@tonic-gate 		}
29987c478bd9Sstevel@tonic-gate 		if (ifreq.ifr_flags & IFF_POINTOPOINT) {
29997c478bd9Sstevel@tonic-gate 			if (ioctl(fd, SIOCGIFDSTADDR, (char *)&ifreq) < 0)
30007c478bd9Sstevel@tonic-gate 				continue;
300161961e0fSrobinson 			/* LINTED pointer cast */
30027c478bd9Sstevel@tonic-gate 			a = ((struct sockaddr_in *)
30037c478bd9Sstevel@tonic-gate 			    &ifreq.ifr_addr)->sin_addr;
30047c478bd9Sstevel@tonic-gate 			if (!in_list(*addrs, i, a))
30057c478bd9Sstevel@tonic-gate 				(*addrs)[i++] = a;
30067c478bd9Sstevel@tonic-gate 			continue;
30077c478bd9Sstevel@tonic-gate 		}
30087c478bd9Sstevel@tonic-gate 	}
30097c478bd9Sstevel@tonic-gate 	if (i == 0 && !use_loopback) {
30107c478bd9Sstevel@tonic-gate 		use_loopback = 1;
30117c478bd9Sstevel@tonic-gate 		goto retry;
30127c478bd9Sstevel@tonic-gate 	}
30137c478bd9Sstevel@tonic-gate 	free(buf);
30147c478bd9Sstevel@tonic-gate 	(void) close(fd);
30157c478bd9Sstevel@tonic-gate 	if (i)
30167c478bd9Sstevel@tonic-gate 		_nderror = ND_OK;
30177c478bd9Sstevel@tonic-gate 	else
30187c478bd9Sstevel@tonic-gate 		free(*addrs);
30197c478bd9Sstevel@tonic-gate 	return (i);
30207c478bd9Sstevel@tonic-gate }
30217c478bd9Sstevel@tonic-gate 
30227c478bd9Sstevel@tonic-gate /*
30237c478bd9Sstevel@tonic-gate  * This is lifted straight from libsocket/inet/inet_mkaddr.c.
30247c478bd9Sstevel@tonic-gate  * Copied here to avoid our dependency on libsocket. More importantly,
30257c478bd9Sstevel@tonic-gate  * to make sure partially static apps that use libnsl, but not
30267c478bd9Sstevel@tonic-gate  * libsocket, don't get screwed up.
30277c478bd9Sstevel@tonic-gate  * If you understand the above paragraph, try to get rid of
30287c478bd9Sstevel@tonic-gate  * this copy of inet_makeaddr; if you don;t, leave it alone.
30297c478bd9Sstevel@tonic-gate  *
30307c478bd9Sstevel@tonic-gate  * Formulate an Internet address from network + host.  Used in
30317c478bd9Sstevel@tonic-gate  * building addresses stored in the ifnet structure.
30327c478bd9Sstevel@tonic-gate  */
30337c478bd9Sstevel@tonic-gate static struct in_addr
_inet_makeaddr(in_addr_t net,in_addr_t host)30347c478bd9Sstevel@tonic-gate _inet_makeaddr(in_addr_t net, in_addr_t host)
30357c478bd9Sstevel@tonic-gate {
30367c478bd9Sstevel@tonic-gate 	in_addr_t addr;
30377c478bd9Sstevel@tonic-gate 	struct in_addr inaddr;
30387c478bd9Sstevel@tonic-gate 
30397c478bd9Sstevel@tonic-gate 	if (net < 128)
30407c478bd9Sstevel@tonic-gate 		addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST);
30417c478bd9Sstevel@tonic-gate 	else if (net < 65536)
30427c478bd9Sstevel@tonic-gate 		addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST);
30437c478bd9Sstevel@tonic-gate 	else if (net < 16777216L)
30447c478bd9Sstevel@tonic-gate 		addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST);
30457c478bd9Sstevel@tonic-gate 	else
30467c478bd9Sstevel@tonic-gate 		addr = net | host;
30477c478bd9Sstevel@tonic-gate 	inaddr.s_addr = htonl(addr);
30487c478bd9Sstevel@tonic-gate 	return (inaddr);
30497c478bd9Sstevel@tonic-gate }
30507c478bd9Sstevel@tonic-gate 
30517c478bd9Sstevel@tonic-gate /*
30527c478bd9Sstevel@tonic-gate  * Routine to read the default configuration file and check if SORT_ADDRS
30537c478bd9Sstevel@tonic-gate  * is set to NO or FALSE. This routine is called by order_haddrlist_af()
30547c478bd9Sstevel@tonic-gate  * to determine if the addresses need to be sorted.
30557c478bd9Sstevel@tonic-gate  */
30567c478bd9Sstevel@tonic-gate static boolean_t
_read_nsw_file(void)30577c478bd9Sstevel@tonic-gate _read_nsw_file(void)
30587c478bd9Sstevel@tonic-gate {
30597c478bd9Sstevel@tonic-gate 	char	defval[LINESIZE];
3060004388ebScasper 	FILE	*defl;
30617c478bd9Sstevel@tonic-gate 	boolean_t	nosort = B_FALSE;
30627c478bd9Sstevel@tonic-gate 
30637c478bd9Sstevel@tonic-gate 
30647c478bd9Sstevel@tonic-gate 	do {
3065004388ebScasper 		defl = fopen(__NSW_DEFAULT_FILE, "rF");
30667c478bd9Sstevel@tonic-gate 	} while ((defl == NULL) && (errno == EINTR));
30677c478bd9Sstevel@tonic-gate 
30687c478bd9Sstevel@tonic-gate 	if (defl == NULL)
30697c478bd9Sstevel@tonic-gate 		return (B_FALSE);
30707c478bd9Sstevel@tonic-gate 
3071004388ebScasper 	while (fgets(defval, sizeof (defval), defl) != NULL) {
30727c478bd9Sstevel@tonic-gate 		if ((strncmp(DONT_SORT, defval, sizeof (DONT_SORT) - 1) == 0) ||
30737c478bd9Sstevel@tonic-gate 		    (strncmp(DONT_SORT2, defval,
30746392794bSMichen Chang 		    sizeof (DONT_SORT2) - 1) == 0)) {
30757c478bd9Sstevel@tonic-gate 			nosort = B_TRUE;
30767c478bd9Sstevel@tonic-gate 			break;
30777c478bd9Sstevel@tonic-gate 		}
30787c478bd9Sstevel@tonic-gate 	}
3079004388ebScasper 	(void) fclose(defl);
30807c478bd9Sstevel@tonic-gate 	return (nosort);
30817c478bd9Sstevel@tonic-gate }
3082