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
5*e11c3f44Smeem  * Common Development and Distribution License (the "License").
6*e11c3f44Smeem  * 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 /*
23*e11c3f44Smeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  * lib/libnsl/nss/netdir_inet_sundry.c
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * This file contains inet-specific implementations of netdir_options,
297c478bd9Sstevel@tonic-gate  * uaddr2taddr, and taddr2uaddr. These implementations
307c478bd9Sstevel@tonic-gate  * used to be in both tcpip.so and switch.so (identical copies).
317c478bd9Sstevel@tonic-gate  * Since we got rid of those, and also it's a good idea to build-in
327c478bd9Sstevel@tonic-gate  * inet-specific implementations in one place, we decided to put
337c478bd9Sstevel@tonic-gate  * them in this file with a not-so glorious name. These are INET-SPECIFIC
347c478bd9Sstevel@tonic-gate  * only, and will not be used for non-inet transports or by third-parties
357c478bd9Sstevel@tonic-gate  * that decide to provide their own nametoaddr libs for inet transports
367c478bd9Sstevel@tonic-gate  * (they are on their own for these as well => they get flexibility).
377c478bd9Sstevel@tonic-gate  *
387c478bd9Sstevel@tonic-gate  * Copied mostly from erstwhile lib/nametoaddr/tcpip/tcpip.c.
397c478bd9Sstevel@tonic-gate  */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include "mt.h"
427c478bd9Sstevel@tonic-gate #include <stdlib.h>
437c478bd9Sstevel@tonic-gate #include <stdio.h>
447c478bd9Sstevel@tonic-gate #include <string.h>
4561961e0fSrobinson #include <strings.h>
467c478bd9Sstevel@tonic-gate #include <unistd.h>
477c478bd9Sstevel@tonic-gate #include <sys/types.h>
487c478bd9Sstevel@tonic-gate #include <sys/stat.h>
497c478bd9Sstevel@tonic-gate #include <fcntl.h>
507c478bd9Sstevel@tonic-gate #include <errno.h>
517c478bd9Sstevel@tonic-gate #include <thread.h>
527c478bd9Sstevel@tonic-gate #include <netconfig.h>
537c478bd9Sstevel@tonic-gate #include <netdir.h>
547c478bd9Sstevel@tonic-gate #include <nss_netdir.h>
557c478bd9Sstevel@tonic-gate #include <tiuser.h>
567c478bd9Sstevel@tonic-gate #include <sys/socket.h>
577c478bd9Sstevel@tonic-gate #include <net/if.h>
587c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
597c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
607c478bd9Sstevel@tonic-gate #include <netinet/in.h>
617c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
627c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
637c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
647c478bd9Sstevel@tonic-gate #include <rpc/types.h>
657c478bd9Sstevel@tonic-gate #include <rpc/rpc_com.h>
667c478bd9Sstevel@tonic-gate #include <syslog.h>
677c478bd9Sstevel@tonic-gate #include <values.h>
687c478bd9Sstevel@tonic-gate #include <limits.h>
697c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
707c478bd9Sstevel@tonic-gate #include "nss.h"
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #define	MAXIFS 32
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * Extracted from socketvar.h
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate #define	SOV_DEFAULT	1	/* Select based on so_default_version */
787c478bd9Sstevel@tonic-gate #define	SOV_SOCKBSD	3	/* Socket with no streams operations */
797c478bd9Sstevel@tonic-gate 
8061961e0fSrobinson extern int _so_socket(int, int, int, char *, int);
8161961e0fSrobinson extern int _so_connect(int, struct sockaddr *, socklen_t, int);
8261961e0fSrobinson extern int _so_getsockname(int, struct sockaddr *, socklen_t *, int);
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate static char *inet_netdir_mergeaddr(struct netconfig *, char *, char *);
867c478bd9Sstevel@tonic-gate static int bindresvport(struct netconfig *, int, struct netbuf *);
877c478bd9Sstevel@tonic-gate static int checkresvport(struct netbuf *);
887c478bd9Sstevel@tonic-gate static struct netbuf *ip_uaddr2taddr(char *);
897c478bd9Sstevel@tonic-gate static struct netbuf *ipv6_uaddr2taddr(char *);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate extern char *inet_ntoa_r(struct in_addr, char *);
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate int
9561961e0fSrobinson __inet_netdir_options(struct netconfig *tp, int opts, int fd, char *par)
967c478bd9Sstevel@tonic-gate {
977c478bd9Sstevel@tonic-gate 	struct nd_mergearg *ma;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	switch (opts) {
1007c478bd9Sstevel@tonic-gate 	case ND_SET_BROADCAST:
1017c478bd9Sstevel@tonic-gate 		/* Every one is allowed to broadcast without asking */
1027c478bd9Sstevel@tonic-gate 		return (ND_OK);
1037c478bd9Sstevel@tonic-gate 	case ND_SET_RESERVEDPORT:	/* bind to a resered port */
10461961e0fSrobinson 		/* LINTED pointer cast */
1057c478bd9Sstevel@tonic-gate 		return (bindresvport(tp, fd, (struct netbuf *)par));
1067c478bd9Sstevel@tonic-gate 	case ND_CHECK_RESERVEDPORT:	/* check if reserved prot */
10761961e0fSrobinson 		/* LINTED pointer cast */
1087c478bd9Sstevel@tonic-gate 		return (checkresvport((struct netbuf *)par));
1097c478bd9Sstevel@tonic-gate 	case ND_MERGEADDR:	/* Merge two addresses */
11061961e0fSrobinson 		/* LINTED pointer cast */
1117c478bd9Sstevel@tonic-gate 		ma = (struct nd_mergearg *)(par);
1127c478bd9Sstevel@tonic-gate 		ma->m_uaddr = inet_netdir_mergeaddr(tp, ma->c_uaddr,
1137c478bd9Sstevel@tonic-gate 		    ma->s_uaddr);
1147c478bd9Sstevel@tonic-gate 		return (_nderror);
1157c478bd9Sstevel@tonic-gate 	default:
1167c478bd9Sstevel@tonic-gate 		return (ND_NOCTRL);
1177c478bd9Sstevel@tonic-gate 	}
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * This routine will convert a TCP/IP internal format address
1237c478bd9Sstevel@tonic-gate  * into a "universal" format address. In our case it prints out the
1247c478bd9Sstevel@tonic-gate  * decimal dot equivalent. h1.h2.h3.h4.p1.p2 where h1-h4 are the host
1257c478bd9Sstevel@tonic-gate  * address and p1-p2 are the port number.
1267c478bd9Sstevel@tonic-gate  */
1277c478bd9Sstevel@tonic-gate char *
12861961e0fSrobinson __inet_taddr2uaddr(struct netconfig *tp, struct netbuf *addr)
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sa;	/* our internal format */
1317c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sa6;	/* our internal format */
1327c478bd9Sstevel@tonic-gate 	char			tmp[RPC_INET6_MAXUADDRSIZE];
1337c478bd9Sstevel@tonic-gate 	unsigned short		myport;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	if (addr == NULL || tp == NULL || addr->buf == NULL) {
1367c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
1377c478bd9Sstevel@tonic-gate 		return (NULL);
1387c478bd9Sstevel@tonic-gate 	}
1397c478bd9Sstevel@tonic-gate 	if (strcmp(tp->nc_protofmly, NC_INET) == 0) {
14061961e0fSrobinson 		/* LINTED pointer cast */
1417c478bd9Sstevel@tonic-gate 		sa = (struct sockaddr_in *)(addr->buf);
1427c478bd9Sstevel@tonic-gate 		myport = ntohs(sa->sin_port);
14361961e0fSrobinson 		(void) inet_ntoa_r(sa->sin_addr, tmp);
1447c478bd9Sstevel@tonic-gate 	} else {
14561961e0fSrobinson 		/* LINTED pointer cast */
1467c478bd9Sstevel@tonic-gate 		sa6 = (struct sockaddr_in6 *)(addr->buf);
1477c478bd9Sstevel@tonic-gate 		myport = ntohs(sa6->sin6_port);
148*e11c3f44Smeem 		if (inet_ntop(AF_INET6, sa6->sin6_addr.s6_addr, tmp,
149*e11c3f44Smeem 		    sizeof (tmp)) == NULL) {
1507c478bd9Sstevel@tonic-gate 			_nderror = ND_BADARG;
1517c478bd9Sstevel@tonic-gate 			return (NULL);
1527c478bd9Sstevel@tonic-gate 		}
1537c478bd9Sstevel@tonic-gate 	}
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	(void) sprintf(tmp + strlen(tmp), ".%d.%d", myport >> 8, myport & 255);
1567c478bd9Sstevel@tonic-gate 	return (strdup(tmp));	/* Doesn't return static data ! */
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate  * This internal routine will convert one of those "universal" addresses
1617c478bd9Sstevel@tonic-gate  * to the internal format used by the Sun TLI TCP/IP provider.
1627c478bd9Sstevel@tonic-gate  */
1637c478bd9Sstevel@tonic-gate struct netbuf *
16461961e0fSrobinson __inet_uaddr2taddr(struct netconfig *tp, char *addr)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate 	if (!addr || !tp) {
1677c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
1687c478bd9Sstevel@tonic-gate 		return (NULL);
1697c478bd9Sstevel@tonic-gate 	}
1707c478bd9Sstevel@tonic-gate 	if (strcmp(tp->nc_protofmly, NC_INET) == 0)
1717c478bd9Sstevel@tonic-gate 		return (ip_uaddr2taddr(addr));
1727c478bd9Sstevel@tonic-gate 	else
1737c478bd9Sstevel@tonic-gate 		return (ipv6_uaddr2taddr(addr));
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate static struct netbuf *
1777c478bd9Sstevel@tonic-gate ip_uaddr2taddr(char *addr)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sa;
1817c478bd9Sstevel@tonic-gate 	uint32_t		inaddr;
1827c478bd9Sstevel@tonic-gate 	unsigned short		inport;
1837c478bd9Sstevel@tonic-gate 	int			h1, h2, h3, h4, p1, p2;
1847c478bd9Sstevel@tonic-gate 	struct netbuf		*result;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	result = malloc(sizeof (struct netbuf));
1877c478bd9Sstevel@tonic-gate 	if (!result) {
1887c478bd9Sstevel@tonic-gate 		_nderror = ND_NOMEM;
1897c478bd9Sstevel@tonic-gate 		return (NULL);
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	sa = calloc(1, sizeof (*sa));
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	if (!sa) {
1957c478bd9Sstevel@tonic-gate 		free(result);
1967c478bd9Sstevel@tonic-gate 		_nderror = ND_NOMEM;
1977c478bd9Sstevel@tonic-gate 		return (NULL);
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	result->buf = (char *)(sa);
2017c478bd9Sstevel@tonic-gate 	result->maxlen = sizeof (struct sockaddr_in);
2027c478bd9Sstevel@tonic-gate 	result->len = sizeof (struct sockaddr_in);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	/* XXX there is probably a better way to do this. */
2057c478bd9Sstevel@tonic-gate 	if (sscanf(addr, "%d.%d.%d.%d.%d.%d", &h1, &h2, &h3, &h4,
2067c478bd9Sstevel@tonic-gate 	    &p1, &p2) != 6) {
2077c478bd9Sstevel@tonic-gate 		free(result);
2087c478bd9Sstevel@tonic-gate 		_nderror = ND_NO_RECOVERY;
2097c478bd9Sstevel@tonic-gate 		return (NULL);
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	/* convert the host address first */
2137c478bd9Sstevel@tonic-gate 	inaddr = (h1 << 24) + (h2 << 16) + (h3 << 8) + h4;
2147c478bd9Sstevel@tonic-gate 	sa->sin_addr.s_addr = htonl(inaddr);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	/* convert the port */
2177c478bd9Sstevel@tonic-gate 	inport = (p1 << 8) + p2;
2187c478bd9Sstevel@tonic-gate 	sa->sin_port = htons(inport);
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	sa->sin_family = AF_INET;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	return (result);
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate static struct netbuf *
2267c478bd9Sstevel@tonic-gate ipv6_uaddr2taddr(char	*addr)
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sa;
2297c478bd9Sstevel@tonic-gate 	unsigned short		inport;
2307c478bd9Sstevel@tonic-gate 	int	 p1, p2;
2317c478bd9Sstevel@tonic-gate 	struct netbuf		*result;
2327c478bd9Sstevel@tonic-gate 	char tmpaddr[RPC_INET6_MAXUADDRSIZE];
2337c478bd9Sstevel@tonic-gate 	char *dot;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	result = malloc(sizeof (struct netbuf));
2367c478bd9Sstevel@tonic-gate 	if (!result) {
2377c478bd9Sstevel@tonic-gate 		_nderror = ND_NOMEM;
2387c478bd9Sstevel@tonic-gate 		return (NULL);
2397c478bd9Sstevel@tonic-gate 	}
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	sa = calloc(1, sizeof (struct sockaddr_in6));
2427c478bd9Sstevel@tonic-gate 	if (!sa) {
2437c478bd9Sstevel@tonic-gate 		free(result);
2447c478bd9Sstevel@tonic-gate 		_nderror = ND_NOMEM;
2457c478bd9Sstevel@tonic-gate 		return (NULL);
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 	result->buf = (char *)(sa);
2487c478bd9Sstevel@tonic-gate 	result->maxlen = sizeof (struct sockaddr_in6);
2497c478bd9Sstevel@tonic-gate 	result->len = sizeof (struct sockaddr_in6);
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	/* retrieve the ipv6 address and port info */
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	if (strlen(addr) > sizeof (tmpaddr) - 1) {
2547c478bd9Sstevel@tonic-gate 		free(result);
2557c478bd9Sstevel@tonic-gate 		_nderror = ND_NOMEM;
2567c478bd9Sstevel@tonic-gate 		return (NULL);
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 
25961961e0fSrobinson 	(void) strcpy(tmpaddr, addr);
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	if ((dot = strrchr(tmpaddr, '.')) != 0) {
2627c478bd9Sstevel@tonic-gate 		*dot = '\0';
2637c478bd9Sstevel@tonic-gate 		p2 = atoi(dot+1);
2647c478bd9Sstevel@tonic-gate 		if ((dot = strrchr(tmpaddr, '.')) != 0) {
2657c478bd9Sstevel@tonic-gate 			*dot = '\0';
2667c478bd9Sstevel@tonic-gate 			p1 = atoi(dot+1);
2677c478bd9Sstevel@tonic-gate 		}
2687c478bd9Sstevel@tonic-gate 	}
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	if (dot == 0) {
2717c478bd9Sstevel@tonic-gate 		free(result);
2727c478bd9Sstevel@tonic-gate 		_nderror = ND_NOMEM;
2737c478bd9Sstevel@tonic-gate 		return (NULL);
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	if (inet_pton(AF_INET6, tmpaddr, sa->sin6_addr.s6_addr) == 0) {
2777c478bd9Sstevel@tonic-gate 		free(result);
2787c478bd9Sstevel@tonic-gate 		_nderror = ND_NOMEM;
2797c478bd9Sstevel@tonic-gate 		return (NULL);
2807c478bd9Sstevel@tonic-gate 	}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	/* convert the port */
2837c478bd9Sstevel@tonic-gate 	inport = (p1 << 8) + p2;
2847c478bd9Sstevel@tonic-gate 	sa->sin6_port = htons(inport);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	sa->sin6_family = AF_INET6;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	return (result);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate /*
2927c478bd9Sstevel@tonic-gate  * Interface caching routines.  The cache is refreshed every
2937c478bd9Sstevel@tonic-gate  * IF_CACHE_REFRESH_TIME seconds.  A read-write lock is used to
2947c478bd9Sstevel@tonic-gate  * protect the cache.
2957c478bd9Sstevel@tonic-gate  */
2967c478bd9Sstevel@tonic-gate #define	IF_CACHE_REFRESH_TIME 10
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate static int if_cache_refresh_time = IF_CACHE_REFRESH_TIME;
2997c478bd9Sstevel@tonic-gate static rwlock_t iflock = DEFAULTRWLOCK;
3007c478bd9Sstevel@tonic-gate static time_t last_updated = 0;		/* protected by iflock */
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate /*
3037c478bd9Sstevel@tonic-gate  * Changing the data type of if_flags from uint_t to uint64_t to accomodate
3047c478bd9Sstevel@tonic-gate  * extra flags. Refer <net/if.h> for the extra flags.
3057c478bd9Sstevel@tonic-gate  */
3067c478bd9Sstevel@tonic-gate typedef struct if_info_s {
3077c478bd9Sstevel@tonic-gate 	struct in_addr if_netmask;	/* netmask in network order */
3087c478bd9Sstevel@tonic-gate 	struct in_addr if_address;	/* address in network order */
3097c478bd9Sstevel@tonic-gate 	uint64_t if_flags;		/* interface flags */
3107c478bd9Sstevel@tonic-gate } if_info_t;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate static if_info_t *if_info = NULL;	/* if cache, protected by iflock */
3137c478bd9Sstevel@tonic-gate static int n_ifs = 0;			/* number of cached interfaces */
3147c478bd9Sstevel@tonic-gate static int numifs_last = 0;		/* number of interfaces last seen */
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate /*
3177c478bd9Sstevel@tonic-gate  * Builds the interface cache.  Write lock on iflock is needed
3187c478bd9Sstevel@tonic-gate  * for calling this routine.  It sets _nderror for error returns.
3197c478bd9Sstevel@tonic-gate  * Returns TRUE if successful, FALSE otherwise.
3207c478bd9Sstevel@tonic-gate  * Changing the structures ifreq and ifconf to lifreq and lifconf to
3217c478bd9Sstevel@tonic-gate  * have larger flag field. This is to accomodate the extra flags associated
3227c478bd9Sstevel@tonic-gate  * with the interface. Also introducing lifn which will contain the number
3237c478bd9Sstevel@tonic-gate  * of IPV4 interfaces present.
3247c478bd9Sstevel@tonic-gate  */
3257c478bd9Sstevel@tonic-gate static bool_t
32661961e0fSrobinson get_if_info(void)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	size_t		needed;
3297c478bd9Sstevel@tonic-gate 	struct lifreq	*buf = NULL;
3307c478bd9Sstevel@tonic-gate 	int		numifs;
3317c478bd9Sstevel@tonic-gate 	struct lifconf  lifc;
3327c478bd9Sstevel@tonic-gate 	struct lifreq   *lifr;
3337c478bd9Sstevel@tonic-gate 	struct lifnum   lifn;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	lifn.lifn_family = AF_INET;
3367c478bd9Sstevel@tonic-gate 	lifn.lifn_flags = 0;
3377c478bd9Sstevel@tonic-gate getifnum:
3387c478bd9Sstevel@tonic-gate 	if (nss_ioctl(AF_INET, SIOCGLIFNUM, &lifn) == -1) {
3397c478bd9Sstevel@tonic-gate 		numifs = MAXIFS;
3407c478bd9Sstevel@tonic-gate 	} else {
3417c478bd9Sstevel@tonic-gate 		numifs = lifn.lifn_count;
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 	/*
3447c478bd9Sstevel@tonic-gate 	 * Add a small fudge factor in case interfaces are plumbed
3457c478bd9Sstevel@tonic-gate 	 * between the SIOCGLIFNUM and SIOCGLIFCONF.
3467c478bd9Sstevel@tonic-gate 	 */
3477c478bd9Sstevel@tonic-gate 	needed = (numifs + 4) * sizeof (struct lifreq);
3487c478bd9Sstevel@tonic-gate 	if (buf == NULL)
3497c478bd9Sstevel@tonic-gate 		buf = malloc(needed);
3507c478bd9Sstevel@tonic-gate 	else
3517c478bd9Sstevel@tonic-gate 		buf = realloc(buf, needed);
3527c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
3537c478bd9Sstevel@tonic-gate 		_nderror = ND_NOMEM;
3547c478bd9Sstevel@tonic-gate 		return (FALSE);
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	lifc.lifc_family = AF_INET;
3587c478bd9Sstevel@tonic-gate 	lifc.lifc_flags = 0;
3597c478bd9Sstevel@tonic-gate 	lifc.lifc_len = needed;
3607c478bd9Sstevel@tonic-gate 	lifc.lifc_buf = (char *)buf;
3617c478bd9Sstevel@tonic-gate 	if (nss_ioctl(AF_INET, SIOCGLIFCONF, &lifc) == -1) {
3627c478bd9Sstevel@tonic-gate 		/*
3637c478bd9Sstevel@tonic-gate 		 * IP returns EINVAL if the buffer was too small to fit
3647c478bd9Sstevel@tonic-gate 		 * all of the entries.  If that's the case, go back and
3657c478bd9Sstevel@tonic-gate 		 * try again.
3667c478bd9Sstevel@tonic-gate 		 */
3677c478bd9Sstevel@tonic-gate 		if (errno == EINVAL)
3687c478bd9Sstevel@tonic-gate 			goto getifnum;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 		free(buf);
3717c478bd9Sstevel@tonic-gate 		free(if_info);
3727c478bd9Sstevel@tonic-gate 		if_info = NULL;
3737c478bd9Sstevel@tonic-gate 		_nderror = ND_SYSTEM;
3747c478bd9Sstevel@tonic-gate 		return (FALSE);
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 	numifs = lifc.lifc_len / (int)sizeof (struct lifreq);
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	if (if_info == NULL || numifs > numifs_last) {
3797c478bd9Sstevel@tonic-gate 		if (if_info == NULL)
3807c478bd9Sstevel@tonic-gate 			if_info = malloc(numifs * sizeof (if_info_t));
3817c478bd9Sstevel@tonic-gate 		else
3827c478bd9Sstevel@tonic-gate 			if_info = realloc(if_info, numifs * sizeof (if_info_t));
3837c478bd9Sstevel@tonic-gate 		if (if_info == NULL) {
3847c478bd9Sstevel@tonic-gate 			free(buf);
3857c478bd9Sstevel@tonic-gate 			_nderror = ND_NOMEM;
3867c478bd9Sstevel@tonic-gate 			return (FALSE);
3877c478bd9Sstevel@tonic-gate 		}
3887c478bd9Sstevel@tonic-gate 		numifs_last = numifs;
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	n_ifs = 0;
3927c478bd9Sstevel@tonic-gate 	for (lifr = buf; lifr < (buf + numifs); lifr++) {
3937c478bd9Sstevel@tonic-gate 		if (lifr->lifr_addr.ss_family != AF_INET)
3947c478bd9Sstevel@tonic-gate 			continue;
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 		if_info[n_ifs].if_address =
397*e11c3f44Smeem 		    ((struct sockaddr_in *)&lifr->lifr_addr)->sin_addr;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 		if (nss_ioctl(AF_INET, SIOCGLIFFLAGS, lifr) < 0)
4007c478bd9Sstevel@tonic-gate 			continue;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 		if ((lifr->lifr_flags & IFF_UP) == 0)
4037c478bd9Sstevel@tonic-gate 			continue;
4047c478bd9Sstevel@tonic-gate 		if_info[n_ifs].if_flags = lifr->lifr_flags;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		if (nss_ioctl(AF_INET, SIOCGLIFNETMASK, lifr) < 0)
4077c478bd9Sstevel@tonic-gate 			continue;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 		if_info[n_ifs].if_netmask =
410*e11c3f44Smeem 		    ((struct sockaddr_in *)&lifr->lifr_addr)->sin_addr;
4117c478bd9Sstevel@tonic-gate 		n_ifs++;
4127c478bd9Sstevel@tonic-gate 	}
4137c478bd9Sstevel@tonic-gate 	free(buf);
4147c478bd9Sstevel@tonic-gate 	return (TRUE);
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate  * Update the interface cache based on last update time.
4207c478bd9Sstevel@tonic-gate  */
4217c478bd9Sstevel@tonic-gate static bool_t
42261961e0fSrobinson update_if_cache(void)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate 	time_t	curtime;
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	(void) rw_wrlock(&iflock);
4277c478bd9Sstevel@tonic-gate 	/*
4287c478bd9Sstevel@tonic-gate 	 * Check if some other thread has beaten this one to it.
4297c478bd9Sstevel@tonic-gate 	 */
4307c478bd9Sstevel@tonic-gate 	(void) time(&curtime);
4317c478bd9Sstevel@tonic-gate 	if ((curtime - last_updated) >= if_cache_refresh_time) {
4327c478bd9Sstevel@tonic-gate 		if (!get_if_info()) {
4337c478bd9Sstevel@tonic-gate 			(void) rw_unlock(&iflock);
4347c478bd9Sstevel@tonic-gate 			return (FALSE);
4357c478bd9Sstevel@tonic-gate 		}
4367c478bd9Sstevel@tonic-gate 		(void) time(&last_updated);
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&iflock);
4397c478bd9Sstevel@tonic-gate 	return (TRUE);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate /*
4447c478bd9Sstevel@tonic-gate  * Given an IP address, check if this matches any of the interface
4457c478bd9Sstevel@tonic-gate  * addresses.  If an error occurs, return FALSE so that the caller
4467c478bd9Sstevel@tonic-gate  * will not assume that this address belongs to this machine.
4477c478bd9Sstevel@tonic-gate  */
4487c478bd9Sstevel@tonic-gate static bool_t
44961961e0fSrobinson is_my_address(struct in_addr addr)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate 	time_t		curtime;
4527c478bd9Sstevel@tonic-gate 	if_info_t	*ifn;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	(void) time(&curtime);
4557c478bd9Sstevel@tonic-gate 	if ((curtime - last_updated) >= if_cache_refresh_time) {
4567c478bd9Sstevel@tonic-gate 		/*
4577c478bd9Sstevel@tonic-gate 		 * Cache needs to be refreshed.
4587c478bd9Sstevel@tonic-gate 		 */
4597c478bd9Sstevel@tonic-gate 		if (!update_if_cache())
4607c478bd9Sstevel@tonic-gate 			return (FALSE);
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&iflock);
4637c478bd9Sstevel@tonic-gate 	for (ifn = if_info; ifn < (if_info + n_ifs); ifn++) {
4647c478bd9Sstevel@tonic-gate 		if (addr.s_addr == ifn->if_address.s_addr) {
4657c478bd9Sstevel@tonic-gate 			(void) rw_unlock(&iflock);
4667c478bd9Sstevel@tonic-gate 			return (TRUE);
4677c478bd9Sstevel@tonic-gate 		}
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&iflock);
4707c478bd9Sstevel@tonic-gate 	return (FALSE);
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate /*
4757c478bd9Sstevel@tonic-gate  * Given a host name, check if it is this host.
4767c478bd9Sstevel@tonic-gate  */
4777c478bd9Sstevel@tonic-gate bool_t
47861961e0fSrobinson __inet_netdir_is_my_host(const char *host)
4797c478bd9Sstevel@tonic-gate {
4807c478bd9Sstevel@tonic-gate 	int		error;
4817c478bd9Sstevel@tonic-gate 	char		buf[NSS_BUFLEN_HOSTS];
4827c478bd9Sstevel@tonic-gate 	struct hostent	res, *h;
4837c478bd9Sstevel@tonic-gate 	char		**c;
4847c478bd9Sstevel@tonic-gate 	struct in_addr	in;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	h = gethostbyname_r(host, (void *)&res, buf, sizeof (buf), &error);
4877c478bd9Sstevel@tonic-gate 	if (h == NULL)
4887c478bd9Sstevel@tonic-gate 		return (FALSE);
4897c478bd9Sstevel@tonic-gate 	if (h->h_addrtype != AF_INET)
4907c478bd9Sstevel@tonic-gate 		return (FALSE);
4917c478bd9Sstevel@tonic-gate 	for (c = h->h_addr_list; *c != NULL; c++) {
49261961e0fSrobinson 		(void) memcpy(&in.s_addr, *c, sizeof (in.s_addr));
4937c478bd9Sstevel@tonic-gate 		if (is_my_address(in))
4947c478bd9Sstevel@tonic-gate 			return (TRUE);
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 	return (FALSE);
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate /*
5017c478bd9Sstevel@tonic-gate  * Given an IP address, find the interface address that has the best
5027c478bd9Sstevel@tonic-gate  * prefix match.  Return the address in network order.
5037c478bd9Sstevel@tonic-gate  */
5047c478bd9Sstevel@tonic-gate static uint32_t
50561961e0fSrobinson get_best_match(struct in_addr addr)
5067c478bd9Sstevel@tonic-gate {
5077c478bd9Sstevel@tonic-gate 	if_info_t *bestmatch, *ifn;
5087c478bd9Sstevel@tonic-gate 	int bestcount, count, limit;
5097c478bd9Sstevel@tonic-gate 	uint32_t mask, netmask, clnt_addr, if_addr;
5107c478bd9Sstevel@tonic-gate 	bool_t found, subnet_match;
5117c478bd9Sstevel@tonic-gate 	int subnet_count;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	bestmatch = NULL;				/* no match yet */
5147c478bd9Sstevel@tonic-gate 	bestcount = BITSPERBYTE * sizeof (uint32_t);	/* worst match */
5157c478bd9Sstevel@tonic-gate 	clnt_addr = ntohl(addr.s_addr);			/* host order */
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	subnet_match = FALSE;		/* subnet match not found yet */
5187c478bd9Sstevel@tonic-gate 	subnet_count = bestcount;	/* worst subnet match */
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	for (ifn = if_info; ifn < (if_info + n_ifs); ifn++) {
5217c478bd9Sstevel@tonic-gate 		netmask = ntohl(ifn->if_netmask.s_addr);  /* host order */
5227c478bd9Sstevel@tonic-gate 		if_addr = ntohl(ifn->if_address.s_addr);  /* host order */
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 		/*
5257c478bd9Sstevel@tonic-gate 		 * set initial count to first bit set in netmask, with
5267c478bd9Sstevel@tonic-gate 		 * zero being the number of the least significant bit.
5277c478bd9Sstevel@tonic-gate 		 */
528*e11c3f44Smeem 		count = 0;
529*e11c3f44Smeem 		for (mask = netmask; mask && ((mask & 1) == 0); mask >>= 1)
530*e11c3f44Smeem 			count++;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 		/*
5337c478bd9Sstevel@tonic-gate 		 * Set limit so that we don't try to match prefixes shorter
5347c478bd9Sstevel@tonic-gate 		 * than the inherent netmask for the class (A, B, C, etc).
5357c478bd9Sstevel@tonic-gate 		 */
5367c478bd9Sstevel@tonic-gate 		if (IN_CLASSC(if_addr))
5377c478bd9Sstevel@tonic-gate 			limit = IN_CLASSC_NSHIFT;
5387c478bd9Sstevel@tonic-gate 		else if (IN_CLASSB(if_addr))
5397c478bd9Sstevel@tonic-gate 			limit = IN_CLASSB_NSHIFT;
5407c478bd9Sstevel@tonic-gate 		else if (IN_CLASSA(if_addr))
5417c478bd9Sstevel@tonic-gate 			limit = IN_CLASSA_NSHIFT;
5427c478bd9Sstevel@tonic-gate 		else
5437c478bd9Sstevel@tonic-gate 			limit = 0;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 		/*
5467c478bd9Sstevel@tonic-gate 		 * We assume that the netmask consists of a contiguous
5477c478bd9Sstevel@tonic-gate 		 * sequence of 1-bits starting with the most significant bit.
5487c478bd9Sstevel@tonic-gate 		 * Prefix comparison starts at the subnet mask level.
5497c478bd9Sstevel@tonic-gate 		 * The prefix mask used for comparison is progressively
5507c478bd9Sstevel@tonic-gate 		 * reduced until it equals the inherent mask for the
5517c478bd9Sstevel@tonic-gate 		 * interface address class.  The algorithm finds an
5527c478bd9Sstevel@tonic-gate 		 * interface in the following order of preference:
5537c478bd9Sstevel@tonic-gate 		 *
5547c478bd9Sstevel@tonic-gate 		 * (1) the longest subnet match
5557c478bd9Sstevel@tonic-gate 		 * (2) the best partial subnet match
5567c478bd9Sstevel@tonic-gate 		 * (3) the first non-loopback && non-PPP interface
5577c478bd9Sstevel@tonic-gate 		 * (4) the first non-loopback interface (PPP is OK)
5587c478bd9Sstevel@tonic-gate 		 */
5597c478bd9Sstevel@tonic-gate 		found = FALSE;
5607c478bd9Sstevel@tonic-gate 		while (netmask && count < subnet_count) {
5617c478bd9Sstevel@tonic-gate 			if ((netmask & clnt_addr) == (netmask & if_addr)) {
5627c478bd9Sstevel@tonic-gate 				bestcount = count;
5637c478bd9Sstevel@tonic-gate 				bestmatch = ifn;
5647c478bd9Sstevel@tonic-gate 				found = TRUE;
5657c478bd9Sstevel@tonic-gate 				break;
5667c478bd9Sstevel@tonic-gate 			}
5677c478bd9Sstevel@tonic-gate 			netmask <<= 1;
5687c478bd9Sstevel@tonic-gate 			count++;
5697c478bd9Sstevel@tonic-gate 			if (count >= bestcount || count > limit || subnet_match)
5707c478bd9Sstevel@tonic-gate 				break;
5717c478bd9Sstevel@tonic-gate 		}
5727c478bd9Sstevel@tonic-gate 		/*
5737c478bd9Sstevel@tonic-gate 		 * If a subnet level match occurred, note this for
5747c478bd9Sstevel@tonic-gate 		 * comparison with future subnet matches.
5757c478bd9Sstevel@tonic-gate 		 */
5767c478bd9Sstevel@tonic-gate 		if (found && (netmask == ntohl(ifn->if_netmask.s_addr))) {
5777c478bd9Sstevel@tonic-gate 			subnet_match = TRUE;
5787c478bd9Sstevel@tonic-gate 			subnet_count = count;
5797c478bd9Sstevel@tonic-gate 		}
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	/*
5837c478bd9Sstevel@tonic-gate 	 * If we don't have a match, select the first interface that
5847c478bd9Sstevel@tonic-gate 	 * is not a loopback interface (and preferably not a PPP interface)
5857c478bd9Sstevel@tonic-gate 	 * as the best match.
5867c478bd9Sstevel@tonic-gate 	 */
5877c478bd9Sstevel@tonic-gate 	if (bestmatch == NULL) {
5887c478bd9Sstevel@tonic-gate 		for (ifn = if_info; ifn < (if_info + n_ifs); ifn++) {
589*e11c3f44Smeem 			if ((ifn->if_flags & IFF_LOOPBACK) == 0) {
5907c478bd9Sstevel@tonic-gate 				bestmatch = ifn;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 				/*
5937c478bd9Sstevel@tonic-gate 				 * If this isn't a PPP interface, we're
5947c478bd9Sstevel@tonic-gate 				 * done.  Otherwise, keep walking through
5957c478bd9Sstevel@tonic-gate 				 * the list in case we have a non-loopback
5967c478bd9Sstevel@tonic-gate 				 * iface that ISN'T a PPP further down our
5977c478bd9Sstevel@tonic-gate 				 * list...
5987c478bd9Sstevel@tonic-gate 				 */
5997c478bd9Sstevel@tonic-gate 				if ((ifn->if_flags & IFF_POINTOPOINT) == 0) {
6007c478bd9Sstevel@tonic-gate 					break;
6017c478bd9Sstevel@tonic-gate 				}
6027c478bd9Sstevel@tonic-gate 			}
6037c478bd9Sstevel@tonic-gate 		}
6047c478bd9Sstevel@tonic-gate 	}
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	if (bestmatch != NULL)
6077c478bd9Sstevel@tonic-gate 		return (bestmatch->if_address.s_addr);
6087c478bd9Sstevel@tonic-gate 	else
6097c478bd9Sstevel@tonic-gate 		return (0);
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate static int
6137c478bd9Sstevel@tonic-gate is_myself(struct sockaddr_in6 *sa6)
6147c478bd9Sstevel@tonic-gate {
6157c478bd9Sstevel@tonic-gate 	struct sioc_addrreq areq;
6167c478bd9Sstevel@tonic-gate 	int s;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	if ((s = open("/dev/udp6", O_RDONLY)) < 0) {
6197c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "is_myself: can't open /dev/udp6: %m");
6207c478bd9Sstevel@tonic-gate 		return (0);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
62361961e0fSrobinson 	(void) memcpy(&areq.sa_addr, sa6, sizeof (struct sockaddr_storage));
6247c478bd9Sstevel@tonic-gate 	areq.sa_res = -1;
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	if (ioctl(s, SIOCTMYADDR, (caddr_t)&areq) < 0) {
6277c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "is_myself:SIOCTMYADDR failed: %m");
62861961e0fSrobinson 		(void) close(s);
6297c478bd9Sstevel@tonic-gate 		return (0);
6307c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate 
63261961e0fSrobinson 	(void) close(s);
6337c478bd9Sstevel@tonic-gate 	return (areq.sa_res);
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate }
6367c478bd9Sstevel@tonic-gate /*
6377c478bd9Sstevel@tonic-gate  * For a given destination address, determine a source address to use.
6387c478bd9Sstevel@tonic-gate  * Returns wildcard address if it cannot determine the source address.
6397c478bd9Sstevel@tonic-gate  * copied from ping.c.
6407c478bd9Sstevel@tonic-gate  */
6417c478bd9Sstevel@tonic-gate union any_in_addr {
6427c478bd9Sstevel@tonic-gate 	struct in6_addr addr6;
6437c478bd9Sstevel@tonic-gate 	struct in_addr addr;
6447c478bd9Sstevel@tonic-gate };
64561961e0fSrobinson 
6467c478bd9Sstevel@tonic-gate static bool_t
6477c478bd9Sstevel@tonic-gate select_server_addr(union any_in_addr *dst_addr, int family,
6487c478bd9Sstevel@tonic-gate     union any_in_addr *src_addr)
6497c478bd9Sstevel@tonic-gate {
6507c478bd9Sstevel@tonic-gate 	struct sockaddr *sock;
6517c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
6527c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
6537c478bd9Sstevel@tonic-gate 	int tmp_fd;
65461961e0fSrobinson 	socklen_t sock_len;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	sock = calloc(1, sizeof (struct sockaddr_in6));
6577c478bd9Sstevel@tonic-gate 	if (sock == NULL) {
6587c478bd9Sstevel@tonic-gate 		return (FALSE);
6597c478bd9Sstevel@tonic-gate 	}
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	if (family == AF_INET) {
66261961e0fSrobinson 		/* LINTED pointer cast */
6637c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)sock;
6647c478bd9Sstevel@tonic-gate 		sin->sin_family = AF_INET;
6657c478bd9Sstevel@tonic-gate 		sin->sin_port = 111;
6667c478bd9Sstevel@tonic-gate 		sin->sin_addr = dst_addr->addr;
6677c478bd9Sstevel@tonic-gate 		sock_len = sizeof (struct sockaddr_in);
6687c478bd9Sstevel@tonic-gate 	} else {
66961961e0fSrobinson 		/* LINTED pointer cast */
6707c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)sock;
6717c478bd9Sstevel@tonic-gate 		sin6->sin6_family = AF_INET6;
6727c478bd9Sstevel@tonic-gate 		sin6->sin6_port = 111;
6737c478bd9Sstevel@tonic-gate 		sin6->sin6_addr = dst_addr->addr6;
6747c478bd9Sstevel@tonic-gate 		sock_len = sizeof (struct sockaddr_in6);
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	/* open a UDP socket */
678*e11c3f44Smeem 	tmp_fd = _so_socket(family, SOCK_DGRAM, 0, NULL, SOV_SOCKBSD);
679*e11c3f44Smeem 	if (tmp_fd < 0) {
680*e11c3f44Smeem 		syslog(LOG_ERR, "select_server_addr: connect failed\n");
6817c478bd9Sstevel@tonic-gate 		return (FALSE);
6827c478bd9Sstevel@tonic-gate 	}
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	/* connect it */
6857c478bd9Sstevel@tonic-gate 	if (_so_connect(tmp_fd, sock, sock_len, SOV_SOCKBSD) < 0) {
6867c478bd9Sstevel@tonic-gate 		/*
6877c478bd9Sstevel@tonic-gate 		 * If there's no route to the destination, this connect() call
6887c478bd9Sstevel@tonic-gate 		 * fails. We just return all-zero (wildcard) as the source
6897c478bd9Sstevel@tonic-gate 		 * address, so that user can get to see "no route to dest"
6907c478bd9Sstevel@tonic-gate 		 * message, as it'll try to send the probe packet out and will
6917c478bd9Sstevel@tonic-gate 		 * receive ICMP unreachable.
6927c478bd9Sstevel@tonic-gate 		 */
693*e11c3f44Smeem 		if (family == AF_INET) {
6947c478bd9Sstevel@tonic-gate 			src_addr->addr.s_addr = INADDR_ANY;
695*e11c3f44Smeem 		} else {
6967c478bd9Sstevel@tonic-gate 			/*
6977c478bd9Sstevel@tonic-gate 			 * Since in6addr_any is not in the scope
6987c478bd9Sstevel@tonic-gate 			 * use the following hack
6997c478bd9Sstevel@tonic-gate 			 */
70061961e0fSrobinson 			(void) memset(src_addr->addr6.s6_addr,
701*e11c3f44Smeem 			    0, sizeof (struct in6_addr));
702*e11c3f44Smeem 		}
7037c478bd9Sstevel@tonic-gate 		(void) close(tmp_fd);
7047c478bd9Sstevel@tonic-gate 		free(sock);
7057c478bd9Sstevel@tonic-gate 		return (FALSE);
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	/* get the local sock info */
7097c478bd9Sstevel@tonic-gate 	if (_so_getsockname(tmp_fd, sock, &sock_len, SOV_DEFAULT) < 0) {
710*e11c3f44Smeem 		syslog(LOG_ERR, "select_server_addr: getsockname failed\n");
7117c478bd9Sstevel@tonic-gate 		(void) close(tmp_fd);
7127c478bd9Sstevel@tonic-gate 		free(sock);
7137c478bd9Sstevel@tonic-gate 		return (FALSE);
7147c478bd9Sstevel@tonic-gate 	}
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	if (family == AF_INET) {
71761961e0fSrobinson 		/* LINTED pointer cast */
7187c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)sock;
7197c478bd9Sstevel@tonic-gate 		src_addr->addr = sin->sin_addr;
7207c478bd9Sstevel@tonic-gate 	} else {
72161961e0fSrobinson 		/* LINTED pointer cast */
7227c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)sock;
7237c478bd9Sstevel@tonic-gate 		src_addr->addr6 = sin6->sin6_addr;
7247c478bd9Sstevel@tonic-gate 	}
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	(void) close(tmp_fd);
7277c478bd9Sstevel@tonic-gate 	free(sock);
7287c478bd9Sstevel@tonic-gate 	return (TRUE);
7297c478bd9Sstevel@tonic-gate }
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate /*
7327c478bd9Sstevel@tonic-gate  * This internal routine will merge one of those "universal" addresses
7337c478bd9Sstevel@tonic-gate  * to the one which will make sense to the remote caller.
7347c478bd9Sstevel@tonic-gate  */
7357c478bd9Sstevel@tonic-gate static char *
73661961e0fSrobinson inet_netdir_mergeaddr(struct netconfig *tp, char *ruaddr, char *uaddr)
7377c478bd9Sstevel@tonic-gate {
7387c478bd9Sstevel@tonic-gate 	char	tmp[SYS_NMLN], *cp;
7397c478bd9Sstevel@tonic-gate 	int	j;
7407c478bd9Sstevel@tonic-gate 	struct	in_addr clientaddr, bestmatch;
7417c478bd9Sstevel@tonic-gate 	time_t	curtime;
7427c478bd9Sstevel@tonic-gate 	int af;
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	if (!uaddr || !ruaddr || !tp) {
7457c478bd9Sstevel@tonic-gate 		_nderror = ND_BADARG;
7467c478bd9Sstevel@tonic-gate 		return (NULL);
7477c478bd9Sstevel@tonic-gate 	}
7487c478bd9Sstevel@tonic-gate 	(void) bzero(tmp, SYS_NMLN);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	if (strcmp(tp->nc_protofmly, NC_INET) == 0)
7517c478bd9Sstevel@tonic-gate 		af = AF_INET;
7527c478bd9Sstevel@tonic-gate 	else
7537c478bd9Sstevel@tonic-gate 		af = AF_INET6;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	if (af == AF_INET) {
7567c478bd9Sstevel@tonic-gate 		if (strncmp(ruaddr, "0.0.0.0.", strlen("0.0.0.0.")) == 0)
7577c478bd9Sstevel@tonic-gate 			/* thats me: return the way it is */
7587c478bd9Sstevel@tonic-gate 			return (strdup(uaddr));
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 		/*
7617c478bd9Sstevel@tonic-gate 		 * Convert remote uaddr into an in_addr so that we can compare
7627c478bd9Sstevel@tonic-gate 		 * to it.  Shave off last two dotted-decimal values.
7637c478bd9Sstevel@tonic-gate 		 */
7647c478bd9Sstevel@tonic-gate 		for (cp = ruaddr, j = 0; j < 4; j++, cp++)
7657c478bd9Sstevel@tonic-gate 			if ((cp = strchr(cp, '.')) == NULL)
7667c478bd9Sstevel@tonic-gate 				break;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 		if (cp != NULL)
7697c478bd9Sstevel@tonic-gate 			*--cp = '\0';	/* null out the dot after the IP addr */
7707c478bd9Sstevel@tonic-gate 		else {
7717c478bd9Sstevel@tonic-gate 			_nderror = ND_NOHOST;
7727c478bd9Sstevel@tonic-gate 			return (NULL);
7737c478bd9Sstevel@tonic-gate 		}
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		clientaddr.s_addr = inet_addr(ruaddr);
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 		/* We know cp is not NULL due to the check above */
7787c478bd9Sstevel@tonic-gate 		*cp = '.';	/* Put the dot back in the IP addr */
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 		(void) time(&curtime);
7817c478bd9Sstevel@tonic-gate 		if ((curtime - last_updated) >= if_cache_refresh_time) {
7827c478bd9Sstevel@tonic-gate 			/*
7837c478bd9Sstevel@tonic-gate 			 * Cache needs to be refreshed.
7847c478bd9Sstevel@tonic-gate 			 */
7857c478bd9Sstevel@tonic-gate 			if (!update_if_cache())
7867c478bd9Sstevel@tonic-gate 				return (NULL);
7877c478bd9Sstevel@tonic-gate 		}
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 		/*
7907c478bd9Sstevel@tonic-gate 		 * Find the best match now.
7917c478bd9Sstevel@tonic-gate 		 */
7927c478bd9Sstevel@tonic-gate 		(void) rw_rdlock(&iflock);
7937c478bd9Sstevel@tonic-gate 		bestmatch.s_addr = get_best_match(clientaddr);
7947c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&iflock);
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 		if (bestmatch.s_addr)
7977c478bd9Sstevel@tonic-gate 			_nderror = ND_OK;
7987c478bd9Sstevel@tonic-gate 		else {
7997c478bd9Sstevel@tonic-gate 			_nderror = ND_NOHOST;
8007c478bd9Sstevel@tonic-gate 			return (NULL);
8017c478bd9Sstevel@tonic-gate 		}
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 		/* prepare the reply */
8047c478bd9Sstevel@tonic-gate 		(void) memset(tmp, '\0', sizeof (tmp));
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 		/* reply consists of the IP addr of the closest interface */
8077c478bd9Sstevel@tonic-gate 		(void) strcpy(tmp, inet_ntoa(bestmatch));
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 		/*
8107c478bd9Sstevel@tonic-gate 		 * ... and the port number part (last two dotted-decimal values)
8117c478bd9Sstevel@tonic-gate 		 * of uaddr
8127c478bd9Sstevel@tonic-gate 		 */
8137c478bd9Sstevel@tonic-gate 		for (cp = uaddr, j = 0; j < 4; j++, cp++)
8147c478bd9Sstevel@tonic-gate 			cp = strchr(cp, '.');
8157c478bd9Sstevel@tonic-gate 		(void) strcat(tmp, --cp);
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	} else {
8187c478bd9Sstevel@tonic-gate 		/* IPv6 */
8197c478bd9Sstevel@tonic-gate 		char *dot;
8207c478bd9Sstevel@tonic-gate 		char *truaddr;
8217c478bd9Sstevel@tonic-gate 		struct sockaddr_in6 sa;
8227c478bd9Sstevel@tonic-gate 		struct sockaddr_in6 server_addr;
8237c478bd9Sstevel@tonic-gate 		union any_in_addr in_addr, out_addr;
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 		if (strncmp(ruaddr, "::", strlen("::")) == 0)
8267c478bd9Sstevel@tonic-gate 			if (*(ruaddr + strlen("::")) == '\0')
8277c478bd9Sstevel@tonic-gate 				/* thats me: return the way it is */
8287c478bd9Sstevel@tonic-gate 				return (strdup(uaddr));
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 		bzero(&sa, sizeof (sa));
8317c478bd9Sstevel@tonic-gate 		bzero(&server_addr, sizeof (server_addr));
8327c478bd9Sstevel@tonic-gate 		truaddr = &tmp[0];
83361961e0fSrobinson 		(void) strcpy(truaddr, ruaddr);
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 		/*
8367c478bd9Sstevel@tonic-gate 		 * now extract the server ip address from
8377c478bd9Sstevel@tonic-gate 		 * the address supplied by client.  It can be
8387c478bd9Sstevel@tonic-gate 		 * client's own IP address.
8397c478bd9Sstevel@tonic-gate 		 */
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 		if ((dot = strrchr(truaddr, '.')) != 0) {
8427c478bd9Sstevel@tonic-gate 			*dot = '\0';
8437c478bd9Sstevel@tonic-gate 			if ((dot = strrchr(truaddr, '.')) != 0)
8447c478bd9Sstevel@tonic-gate 				*dot = '\0';
8457c478bd9Sstevel@tonic-gate 		}
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 		if (dot == 0) {
8487c478bd9Sstevel@tonic-gate 			_nderror = ND_NOHOST;
8497c478bd9Sstevel@tonic-gate 			return (NULL);
8507c478bd9Sstevel@tonic-gate 		}
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 		if (inet_pton(af, truaddr, sa.sin6_addr.s6_addr)
8537c478bd9Sstevel@tonic-gate 		    != 1) {
8547c478bd9Sstevel@tonic-gate 			_nderror = ND_NOHOST;
8557c478bd9Sstevel@tonic-gate 			return (NULL);
8567c478bd9Sstevel@tonic-gate 		}
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 		in_addr.addr6 = sa.sin6_addr;
8597c478bd9Sstevel@tonic-gate 		sa.sin6_family = AF_INET6;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 		/* is it my IP address */
8627c478bd9Sstevel@tonic-gate 		if (!is_myself(&sa)) {
8637c478bd9Sstevel@tonic-gate 			/* have the kernel select one for me */
8647c478bd9Sstevel@tonic-gate 			if (select_server_addr(&in_addr, af, &out_addr) ==
8657c478bd9Sstevel@tonic-gate 			    FALSE)
8667c478bd9Sstevel@tonic-gate 				return (NULL);
8677c478bd9Sstevel@tonic-gate 			server_addr.sin6_addr = out_addr.addr6;
868*e11c3f44Smeem 		} else {
869*e11c3f44Smeem 			(void) memcpy(&server_addr, &sa, sizeof (server_addr));
8707c478bd9Sstevel@tonic-gate 		}
871*e11c3f44Smeem 
872*e11c3f44Smeem 		if (inet_ntop(af, server_addr.sin6_addr.s6_addr, tmp,
873*e11c3f44Smeem 		    sizeof (tmp)) == NULL) {
8747c478bd9Sstevel@tonic-gate 			_nderror = ND_NOHOST;
8757c478bd9Sstevel@tonic-gate 			return (NULL);
8767c478bd9Sstevel@tonic-gate 		}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 		/* now extract the port info */
8797c478bd9Sstevel@tonic-gate 		if ((dot = strrchr(uaddr, '.')) != 0) {
880*e11c3f44Smeem 			char *p = --dot;
8817c478bd9Sstevel@tonic-gate 
882*e11c3f44Smeem 			while (*p-- != '.')
883*e11c3f44Smeem 				;
8847c478bd9Sstevel@tonic-gate 			p++;
88561961e0fSrobinson 			(void) strcat(tmp + strlen(tmp), p);
8867c478bd9Sstevel@tonic-gate 			_nderror = ND_OK;
8877c478bd9Sstevel@tonic-gate 		} else {
8887c478bd9Sstevel@tonic-gate 			_nderror = ND_NOHOST;
8897c478bd9Sstevel@tonic-gate 			return (NULL);
8907c478bd9Sstevel@tonic-gate 		}
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate 	return (strdup(tmp));
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate static int
89761961e0fSrobinson bindresvport(struct netconfig *nconf, int fd, struct netbuf *addr)
8987c478bd9Sstevel@tonic-gate {
8997c478bd9Sstevel@tonic-gate 	int res;
9007c478bd9Sstevel@tonic-gate 	struct sockaddr_in myaddr;
9017c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 myaddr6;
9027c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
9037c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
9047c478bd9Sstevel@tonic-gate 	int i;
9057c478bd9Sstevel@tonic-gate 	struct t_bind tbindstr, *tres;
9067c478bd9Sstevel@tonic-gate 	struct t_info tinfo;
9077c478bd9Sstevel@tonic-gate 	struct t_optmgmt req, resp;
9087c478bd9Sstevel@tonic-gate 	struct opthdr *opt;
9097c478bd9Sstevel@tonic-gate 	int reqbuf[64/sizeof (int)];
9107c478bd9Sstevel@tonic-gate 	int *optval;
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	union {
9137c478bd9Sstevel@tonic-gate 		struct sockaddr_in *sin;
9147c478bd9Sstevel@tonic-gate 		struct sockaddr_in6 *sin6;
9157c478bd9Sstevel@tonic-gate 		char *buf;
9167c478bd9Sstevel@tonic-gate 	} u;
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	_nderror = ND_SYSTEM;
9197c478bd9Sstevel@tonic-gate 	if (geteuid()) {
9207c478bd9Sstevel@tonic-gate 		errno = EACCES;
9217c478bd9Sstevel@tonic-gate 		return (-1);
9227c478bd9Sstevel@tonic-gate 	}
9237c478bd9Sstevel@tonic-gate 	if ((i = t_getstate(fd)) != T_UNBND) {
9247c478bd9Sstevel@tonic-gate 		if (t_errno == TBADF)
9257c478bd9Sstevel@tonic-gate 			errno = EBADF;
9267c478bd9Sstevel@tonic-gate 		if (i != -1)
9277c478bd9Sstevel@tonic-gate 			errno = EISCONN;
9287c478bd9Sstevel@tonic-gate 		return (-1);
9297c478bd9Sstevel@tonic-gate 	}
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
9327c478bd9Sstevel@tonic-gate 		if (addr == NULL) {
9337c478bd9Sstevel@tonic-gate 			sin = &myaddr;
93461961e0fSrobinson 			(void) memset(sin, 0, sizeof (*sin));
9357c478bd9Sstevel@tonic-gate 			sin->sin_family = AF_INET;
9367c478bd9Sstevel@tonic-gate 			u.buf = (char *)sin;
9377c478bd9Sstevel@tonic-gate 		} else
9387c478bd9Sstevel@tonic-gate 			u.buf = (char *)addr->buf;
9397c478bd9Sstevel@tonic-gate 	} else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
9407c478bd9Sstevel@tonic-gate 		if (addr == NULL) {
9417c478bd9Sstevel@tonic-gate 			sin6 = &myaddr6;
94261961e0fSrobinson 			(void) memset(sin6, 0, sizeof (*sin6));
9437c478bd9Sstevel@tonic-gate 			sin6->sin6_family = AF_INET6;
9447c478bd9Sstevel@tonic-gate 			u.buf = (char *)sin6;
9457c478bd9Sstevel@tonic-gate 		} else
9467c478bd9Sstevel@tonic-gate 			u.buf = addr->buf;
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	} else {
9497c478bd9Sstevel@tonic-gate 		errno = EPFNOSUPPORT;
9507c478bd9Sstevel@tonic-gate 		return (-1);
9517c478bd9Sstevel@tonic-gate 	}
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	/* Transform sockaddr_in to netbuf */
9547c478bd9Sstevel@tonic-gate 	if (t_getinfo(fd, &tinfo) == -1)
9557c478bd9Sstevel@tonic-gate 		return (-1);
95661961e0fSrobinson 	/* LINTED pointer cast */
9577c478bd9Sstevel@tonic-gate 	tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
9587c478bd9Sstevel@tonic-gate 	if (tres == NULL) {
9597c478bd9Sstevel@tonic-gate 		_nderror = ND_NOMEM;
9607c478bd9Sstevel@tonic-gate 		return (-1);
9617c478bd9Sstevel@tonic-gate 	}
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	tbindstr.qlen = 0; /* Always 0; user should change if he wants to */
9647c478bd9Sstevel@tonic-gate 	tbindstr.addr.buf = (char *)u.buf;
9657c478bd9Sstevel@tonic-gate 	tbindstr.addr.len = tbindstr.addr.maxlen = __rpc_get_a_size(tinfo.addr);
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	/*
9687c478bd9Sstevel@tonic-gate 	 * Use *_ANONPRIVBIND to ask the kernel to pick a port in the
9697c478bd9Sstevel@tonic-gate 	 * priviledged range for us.
9707c478bd9Sstevel@tonic-gate 	 */
9717c478bd9Sstevel@tonic-gate 	opt = (struct opthdr *)reqbuf;
9727c478bd9Sstevel@tonic-gate 	if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
9737c478bd9Sstevel@tonic-gate 		opt->level = IPPROTO_TCP;
9747c478bd9Sstevel@tonic-gate 		opt->name = TCP_ANONPRIVBIND;
9757c478bd9Sstevel@tonic-gate 	} else if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
9767c478bd9Sstevel@tonic-gate 		opt->level = IPPROTO_UDP;
9777c478bd9Sstevel@tonic-gate 		opt->name = UDP_ANONPRIVBIND;
9787c478bd9Sstevel@tonic-gate 	} else {
9797c478bd9Sstevel@tonic-gate 		errno = EPROTONOSUPPORT;
9807c478bd9Sstevel@tonic-gate 		(void) t_free((char *)tres, T_BIND);
9817c478bd9Sstevel@tonic-gate 		return (-1);
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	opt->len = sizeof (int);
9857c478bd9Sstevel@tonic-gate 	req.flags = T_NEGOTIATE;
9867c478bd9Sstevel@tonic-gate 	req.opt.len = sizeof (struct opthdr) + opt->len;
9877c478bd9Sstevel@tonic-gate 	req.opt.buf = (char *)opt;
98861961e0fSrobinson 	/* LINTED pointer cast */
9897c478bd9Sstevel@tonic-gate 	optval = (int *)((char *)reqbuf + sizeof (struct opthdr));
9907c478bd9Sstevel@tonic-gate 	*optval = 1;
9917c478bd9Sstevel@tonic-gate 	resp.flags = 0;
9927c478bd9Sstevel@tonic-gate 	resp.opt.buf = (char *)reqbuf;
9937c478bd9Sstevel@tonic-gate 	resp.opt.maxlen = sizeof (reqbuf);
9947c478bd9Sstevel@tonic-gate 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
9957c478bd9Sstevel@tonic-gate 		(void) t_free((char *)tres, T_BIND);
9967c478bd9Sstevel@tonic-gate 		return (-1);
9977c478bd9Sstevel@tonic-gate 	}
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	if (u.sin->sin_family == AF_INET)
10007c478bd9Sstevel@tonic-gate 		u.sin->sin_port = htons(0);
10017c478bd9Sstevel@tonic-gate 	else
10027c478bd9Sstevel@tonic-gate 		u.sin6->sin6_port = htons(0);
10037c478bd9Sstevel@tonic-gate 	res = t_bind(fd, &tbindstr, tres);
10047c478bd9Sstevel@tonic-gate 	if (res != 0) {
10057c478bd9Sstevel@tonic-gate 		if (t_errno == TNOADDR) {
10067c478bd9Sstevel@tonic-gate 			_nderror = ND_FAILCTRL;
10077c478bd9Sstevel@tonic-gate 			res = 1;
10087c478bd9Sstevel@tonic-gate 		}
10097c478bd9Sstevel@tonic-gate 	} else {
10107c478bd9Sstevel@tonic-gate 		_nderror = ND_OK;
10117c478bd9Sstevel@tonic-gate 	}
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	/*
10147c478bd9Sstevel@tonic-gate 	 * Always turn off the option when we are done.  Note that by doing
10157c478bd9Sstevel@tonic-gate 	 * this, if the caller has set this option before calling
10167c478bd9Sstevel@tonic-gate 	 * bindresvport(), it will be unset.  Better be safe...
10177c478bd9Sstevel@tonic-gate 	 */
1018*e11c3f44Smeem 	*optval = 0;
10197c478bd9Sstevel@tonic-gate 	resp.flags = 0;
10207c478bd9Sstevel@tonic-gate 	resp.opt.buf = (char *)reqbuf;
10217c478bd9Sstevel@tonic-gate 	resp.opt.maxlen = sizeof (reqbuf);
10227c478bd9Sstevel@tonic-gate 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
10237c478bd9Sstevel@tonic-gate 		(void) t_free((char *)tres, T_BIND);
10247c478bd9Sstevel@tonic-gate 		if (res == 0)
10257c478bd9Sstevel@tonic-gate 			(void) t_unbind(fd);
10267c478bd9Sstevel@tonic-gate 		_nderror = ND_FAILCTRL;
10277c478bd9Sstevel@tonic-gate 		return (-1);
10287c478bd9Sstevel@tonic-gate 	}
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	(void) t_free((char *)tres, T_BIND);
10317c478bd9Sstevel@tonic-gate 	return (res);
10327c478bd9Sstevel@tonic-gate }
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate static int
103561961e0fSrobinson checkresvport(struct netbuf *addr)
10367c478bd9Sstevel@tonic-gate {
10377c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
10387c478bd9Sstevel@tonic-gate 	unsigned short port;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	if (addr == NULL) {
10417c478bd9Sstevel@tonic-gate 		_nderror = ND_FAILCTRL;
10427c478bd9Sstevel@tonic-gate 		return (-1);
10437c478bd9Sstevel@tonic-gate 	}
10447c478bd9Sstevel@tonic-gate 	/*
10457c478bd9Sstevel@tonic-gate 	 * Still works for IPv6 since the first two memebers of
10467c478bd9Sstevel@tonic-gate 	 * both address structure point to family and port # respectively
10477c478bd9Sstevel@tonic-gate 	 */
104861961e0fSrobinson 	/* LINTED pointer cast */
10497c478bd9Sstevel@tonic-gate 	sin = (struct sockaddr_in *)(addr->buf);
10507c478bd9Sstevel@tonic-gate 	port = ntohs(sin->sin_port);
10517c478bd9Sstevel@tonic-gate 	if (port < IPPORT_RESERVED)
10527c478bd9Sstevel@tonic-gate 		return (0);
10537c478bd9Sstevel@tonic-gate 	return (1);
10547c478bd9Sstevel@tonic-gate }
1055