1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  *
26*0Sstevel@tonic-gate  * lib/libnsl/nss/netdir_inet_sundry.c
27*0Sstevel@tonic-gate  *
28*0Sstevel@tonic-gate  * This file contains inet-specific implementations of netdir_options,
29*0Sstevel@tonic-gate  * uaddr2taddr, and taddr2uaddr. These implementations
30*0Sstevel@tonic-gate  * used to be in both tcpip.so and switch.so (identical copies).
31*0Sstevel@tonic-gate  * Since we got rid of those, and also it's a good idea to build-in
32*0Sstevel@tonic-gate  * inet-specific implementations in one place, we decided to put
33*0Sstevel@tonic-gate  * them in this file with a not-so glorious name. These are INET-SPECIFIC
34*0Sstevel@tonic-gate  * only, and will not be used for non-inet transports or by third-parties
35*0Sstevel@tonic-gate  * that decide to provide their own nametoaddr libs for inet transports
36*0Sstevel@tonic-gate  * (they are on their own for these as well => they get flexibility).
37*0Sstevel@tonic-gate  *
38*0Sstevel@tonic-gate  * Copied mostly from erstwhile lib/nametoaddr/tcpip/tcpip.c.
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #include "mt.h"
44*0Sstevel@tonic-gate #include <stdlib.h>
45*0Sstevel@tonic-gate #include <stdio.h>
46*0Sstevel@tonic-gate #include <string.h>
47*0Sstevel@tonic-gate #include <unistd.h>
48*0Sstevel@tonic-gate #include <sys/types.h>
49*0Sstevel@tonic-gate #include <sys/stat.h>
50*0Sstevel@tonic-gate #include <fcntl.h>
51*0Sstevel@tonic-gate #include <errno.h>
52*0Sstevel@tonic-gate #include <thread.h>
53*0Sstevel@tonic-gate #include <netconfig.h>
54*0Sstevel@tonic-gate #include <netdir.h>
55*0Sstevel@tonic-gate #include <nss_netdir.h>
56*0Sstevel@tonic-gate #include <tiuser.h>
57*0Sstevel@tonic-gate #include <sys/socket.h>
58*0Sstevel@tonic-gate #include <net/if.h>
59*0Sstevel@tonic-gate #include <sys/sockio.h>
60*0Sstevel@tonic-gate #include <sys/fcntl.h>
61*0Sstevel@tonic-gate #include <netinet/in.h>
62*0Sstevel@tonic-gate #include <netinet/tcp.h>
63*0Sstevel@tonic-gate #include <netinet/udp.h>
64*0Sstevel@tonic-gate #include <arpa/inet.h>
65*0Sstevel@tonic-gate #include <rpc/types.h>
66*0Sstevel@tonic-gate #include <rpc/trace.h>
67*0Sstevel@tonic-gate #include <rpc/rpc_com.h>
68*0Sstevel@tonic-gate #include <syslog.h>
69*0Sstevel@tonic-gate #include <values.h>
70*0Sstevel@tonic-gate #include <limits.h>
71*0Sstevel@tonic-gate #ifdef DEBUG
72*0Sstevel@tonic-gate #include <stdio.h>
73*0Sstevel@tonic-gate #endif
74*0Sstevel@tonic-gate #include <nss_dbdefs.h>
75*0Sstevel@tonic-gate #include "nss.h"
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate #define	MAXIFS 32
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate /*
80*0Sstevel@tonic-gate  * Extracted from socketvar.h
81*0Sstevel@tonic-gate  */
82*0Sstevel@tonic-gate #define	SOV_DEFAULT	1	/* Select based on so_default_version */
83*0Sstevel@tonic-gate #define	SOV_SOCKBSD	3	/* Socket with no streams operations */
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate extern int _so_socket();
86*0Sstevel@tonic-gate extern int _so_connect();
87*0Sstevel@tonic-gate extern int _so_getsockname();
88*0Sstevel@tonic-gate extern int bzero();
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate static char *inet_netdir_mergeaddr(struct netconfig *, char *, char *);
92*0Sstevel@tonic-gate static int bindresvport(struct netconfig *, int, struct netbuf *);
93*0Sstevel@tonic-gate static int checkresvport(struct netbuf *);
94*0Sstevel@tonic-gate static struct netbuf *ip_uaddr2taddr(char *);
95*0Sstevel@tonic-gate static struct netbuf *ipv6_uaddr2taddr(char *);
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate extern char *inet_ntoa_r(struct in_addr, char *);
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate int
101*0Sstevel@tonic-gate __inet_netdir_options(tp, opts, fd, par)
102*0Sstevel@tonic-gate 	struct netconfig *tp;
103*0Sstevel@tonic-gate 	int opts;
104*0Sstevel@tonic-gate 	int fd;
105*0Sstevel@tonic-gate 	char *par;
106*0Sstevel@tonic-gate {
107*0Sstevel@tonic-gate 	struct nd_mergearg *ma;
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	switch (opts) {
110*0Sstevel@tonic-gate 	case ND_SET_BROADCAST:
111*0Sstevel@tonic-gate 		/* Every one is allowed to broadcast without asking */
112*0Sstevel@tonic-gate 		return (ND_OK);
113*0Sstevel@tonic-gate 	case ND_SET_RESERVEDPORT:	/* bind to a resered port */
114*0Sstevel@tonic-gate 		return (bindresvport(tp, fd, (struct netbuf *)par));
115*0Sstevel@tonic-gate 	case ND_CHECK_RESERVEDPORT:	/* check if reserved prot */
116*0Sstevel@tonic-gate 		return (checkresvport((struct netbuf *)par));
117*0Sstevel@tonic-gate 	case ND_MERGEADDR:	/* Merge two addresses */
118*0Sstevel@tonic-gate 		ma = (struct nd_mergearg *)(par);
119*0Sstevel@tonic-gate 		ma->m_uaddr = inet_netdir_mergeaddr(tp, ma->c_uaddr,
120*0Sstevel@tonic-gate 		    ma->s_uaddr);
121*0Sstevel@tonic-gate 		return (_nderror);
122*0Sstevel@tonic-gate 	default:
123*0Sstevel@tonic-gate 		return (ND_NOCTRL);
124*0Sstevel@tonic-gate 	}
125*0Sstevel@tonic-gate }
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate /*
129*0Sstevel@tonic-gate  * This routine will convert a TCP/IP internal format address
130*0Sstevel@tonic-gate  * into a "universal" format address. In our case it prints out the
131*0Sstevel@tonic-gate  * decimal dot equivalent. h1.h2.h3.h4.p1.p2 where h1-h4 are the host
132*0Sstevel@tonic-gate  * address and p1-p2 are the port number.
133*0Sstevel@tonic-gate  */
134*0Sstevel@tonic-gate char *
135*0Sstevel@tonic-gate __inet_taddr2uaddr(tp, addr)
136*0Sstevel@tonic-gate 	struct netconfig	*tp;	/* the transport provider */
137*0Sstevel@tonic-gate 	struct netbuf		*addr;	/* the netbuf struct */
138*0Sstevel@tonic-gate {
139*0Sstevel@tonic-gate 	struct sockaddr_in	*sa;	/* our internal format */
140*0Sstevel@tonic-gate 	struct sockaddr_in6	*sa6;	/* our internal format */
141*0Sstevel@tonic-gate 	char			tmp[RPC_INET6_MAXUADDRSIZE];
142*0Sstevel@tonic-gate 	unsigned short		myport;
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	if (addr == NULL || tp == NULL || addr->buf == NULL) {
145*0Sstevel@tonic-gate 		_nderror = ND_BADARG;
146*0Sstevel@tonic-gate 		return (NULL);
147*0Sstevel@tonic-gate 	}
148*0Sstevel@tonic-gate 	if (strcmp(tp->nc_protofmly, NC_INET) == 0) {
149*0Sstevel@tonic-gate 		sa = (struct sockaddr_in *)(addr->buf);
150*0Sstevel@tonic-gate 		myport = ntohs(sa->sin_port);
151*0Sstevel@tonic-gate 		inet_ntoa_r(sa->sin_addr, tmp);
152*0Sstevel@tonic-gate 	} else {
153*0Sstevel@tonic-gate 		sa6 = (struct sockaddr_in6 *)(addr->buf);
154*0Sstevel@tonic-gate 		myport = ntohs(sa6->sin6_port);
155*0Sstevel@tonic-gate 		if (inet_ntop(AF_INET6, (void *)sa6->sin6_addr.s6_addr,
156*0Sstevel@tonic-gate 			tmp, sizeof (tmp)) == 0) {
157*0Sstevel@tonic-gate 			_nderror = ND_BADARG;
158*0Sstevel@tonic-gate 			return (NULL);
159*0Sstevel@tonic-gate 		}
160*0Sstevel@tonic-gate 	}
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	(void) sprintf(tmp + strlen(tmp), ".%d.%d", myport >> 8, myport & 255);
163*0Sstevel@tonic-gate 	return (strdup(tmp));	/* Doesn't return static data ! */
164*0Sstevel@tonic-gate }
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate /*
167*0Sstevel@tonic-gate  * This internal routine will convert one of those "universal" addresses
168*0Sstevel@tonic-gate  * to the internal format used by the Sun TLI TCP/IP provider.
169*0Sstevel@tonic-gate  */
170*0Sstevel@tonic-gate struct netbuf *
171*0Sstevel@tonic-gate __inet_uaddr2taddr(tp, addr)
172*0Sstevel@tonic-gate 	struct netconfig	*tp;	/* the transport provider */
173*0Sstevel@tonic-gate 	char			*addr;	/* the address */
174*0Sstevel@tonic-gate {
175*0Sstevel@tonic-gate 	if (!addr || !tp) {
176*0Sstevel@tonic-gate 		_nderror = ND_BADARG;
177*0Sstevel@tonic-gate 		return (NULL);
178*0Sstevel@tonic-gate 	}
179*0Sstevel@tonic-gate 	if (strcmp(tp->nc_protofmly, NC_INET) == 0)
180*0Sstevel@tonic-gate 		return (ip_uaddr2taddr(addr));
181*0Sstevel@tonic-gate 	else
182*0Sstevel@tonic-gate 		return (ipv6_uaddr2taddr(addr));
183*0Sstevel@tonic-gate }
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate static struct netbuf *
186*0Sstevel@tonic-gate ip_uaddr2taddr(char *addr)
187*0Sstevel@tonic-gate {
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	struct sockaddr_in	*sa;
190*0Sstevel@tonic-gate 	uint32_t		inaddr;
191*0Sstevel@tonic-gate 	unsigned short		inport;
192*0Sstevel@tonic-gate 	int			h1, h2, h3, h4, p1, p2;
193*0Sstevel@tonic-gate 	struct netbuf		*result;
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	result = malloc(sizeof (struct netbuf));
196*0Sstevel@tonic-gate 	if (!result) {
197*0Sstevel@tonic-gate 		_nderror = ND_NOMEM;
198*0Sstevel@tonic-gate 		return (NULL);
199*0Sstevel@tonic-gate 	}
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	sa = calloc(1, sizeof (*sa));
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	if (!sa) {
204*0Sstevel@tonic-gate 		free(result);
205*0Sstevel@tonic-gate 		_nderror = ND_NOMEM;
206*0Sstevel@tonic-gate 		return (NULL);
207*0Sstevel@tonic-gate 	}
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	result->buf = (char *)(sa);
210*0Sstevel@tonic-gate 	result->maxlen = sizeof (struct sockaddr_in);
211*0Sstevel@tonic-gate 	result->len = sizeof (struct sockaddr_in);
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	/* XXX there is probably a better way to do this. */
214*0Sstevel@tonic-gate 	if (sscanf(addr, "%d.%d.%d.%d.%d.%d", &h1, &h2, &h3, &h4,
215*0Sstevel@tonic-gate 	    &p1, &p2) != 6) {
216*0Sstevel@tonic-gate 		free(result);
217*0Sstevel@tonic-gate 		_nderror = ND_NO_RECOVERY;
218*0Sstevel@tonic-gate 		return (NULL);
219*0Sstevel@tonic-gate 	}
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	/* convert the host address first */
222*0Sstevel@tonic-gate 	inaddr = (h1 << 24) + (h2 << 16) + (h3 << 8) + h4;
223*0Sstevel@tonic-gate 	sa->sin_addr.s_addr = htonl(inaddr);
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	/* convert the port */
226*0Sstevel@tonic-gate 	inport = (p1 << 8) + p2;
227*0Sstevel@tonic-gate 	sa->sin_port = htons(inport);
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	sa->sin_family = AF_INET;
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	return (result);
232*0Sstevel@tonic-gate }
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate static struct netbuf *
235*0Sstevel@tonic-gate ipv6_uaddr2taddr(char	*addr)
236*0Sstevel@tonic-gate {
237*0Sstevel@tonic-gate 	struct sockaddr_in6	*sa;
238*0Sstevel@tonic-gate 	unsigned short		inport;
239*0Sstevel@tonic-gate 	int	 p1, p2;
240*0Sstevel@tonic-gate 	struct netbuf		*result;
241*0Sstevel@tonic-gate 	char tmpaddr[RPC_INET6_MAXUADDRSIZE];
242*0Sstevel@tonic-gate 	char *dot;
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 	result = malloc(sizeof (struct netbuf));
245*0Sstevel@tonic-gate 	if (!result) {
246*0Sstevel@tonic-gate 		_nderror = ND_NOMEM;
247*0Sstevel@tonic-gate 		return (NULL);
248*0Sstevel@tonic-gate 	}
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	sa = calloc(1, sizeof (struct sockaddr_in6));
251*0Sstevel@tonic-gate 	if (!sa) {
252*0Sstevel@tonic-gate 		free(result);
253*0Sstevel@tonic-gate 		_nderror = ND_NOMEM;
254*0Sstevel@tonic-gate 		return (NULL);
255*0Sstevel@tonic-gate 	}
256*0Sstevel@tonic-gate 	result->buf = (char *)(sa);
257*0Sstevel@tonic-gate 	result->maxlen = sizeof (struct sockaddr_in6);
258*0Sstevel@tonic-gate 	result->len = sizeof (struct sockaddr_in6);
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	/* retrieve the ipv6 address and port info */
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	if (strlen(addr) > sizeof (tmpaddr) - 1) {
263*0Sstevel@tonic-gate 		free(result);
264*0Sstevel@tonic-gate 		_nderror = ND_NOMEM;
265*0Sstevel@tonic-gate 		return (NULL);
266*0Sstevel@tonic-gate 	}
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	strcpy(tmpaddr, addr);
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	if ((dot = strrchr(tmpaddr, '.')) != 0) {
271*0Sstevel@tonic-gate 		*dot = '\0';
272*0Sstevel@tonic-gate 		p2 = atoi(dot+1);
273*0Sstevel@tonic-gate 		if ((dot = strrchr(tmpaddr, '.')) != 0) {
274*0Sstevel@tonic-gate 			*dot = '\0';
275*0Sstevel@tonic-gate 			p1 = atoi(dot+1);
276*0Sstevel@tonic-gate 		}
277*0Sstevel@tonic-gate 	}
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	if (dot == 0) {
280*0Sstevel@tonic-gate 		free(result);
281*0Sstevel@tonic-gate 		_nderror = ND_NOMEM;
282*0Sstevel@tonic-gate 		return (NULL);
283*0Sstevel@tonic-gate 	}
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	if (inet_pton(AF_INET6, tmpaddr, sa->sin6_addr.s6_addr) == 0) {
286*0Sstevel@tonic-gate 		free(result);
287*0Sstevel@tonic-gate 		_nderror = ND_NOMEM;
288*0Sstevel@tonic-gate 		return (NULL);
289*0Sstevel@tonic-gate 	}
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	/* convert the port */
292*0Sstevel@tonic-gate 	inport = (p1 << 8) + p2;
293*0Sstevel@tonic-gate 	sa->sin6_port = htons(inport);
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	sa->sin6_family = AF_INET6;
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 	return (result);
298*0Sstevel@tonic-gate }
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate /*
301*0Sstevel@tonic-gate  * Interface caching routines.  The cache is refreshed every
302*0Sstevel@tonic-gate  * IF_CACHE_REFRESH_TIME seconds.  A read-write lock is used to
303*0Sstevel@tonic-gate  * protect the cache.
304*0Sstevel@tonic-gate  */
305*0Sstevel@tonic-gate #define	IF_CACHE_REFRESH_TIME 10
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate static int if_cache_refresh_time = IF_CACHE_REFRESH_TIME;
308*0Sstevel@tonic-gate static rwlock_t iflock = DEFAULTRWLOCK;
309*0Sstevel@tonic-gate static time_t last_updated = 0;		/* protected by iflock */
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate /*
312*0Sstevel@tonic-gate  * Changing the data type of if_flags from uint_t to uint64_t to accomodate
313*0Sstevel@tonic-gate  * extra flags. Refer <net/if.h> for the extra flags.
314*0Sstevel@tonic-gate  */
315*0Sstevel@tonic-gate typedef struct if_info_s {
316*0Sstevel@tonic-gate 	struct in_addr if_netmask;	/* netmask in network order */
317*0Sstevel@tonic-gate 	struct in_addr if_address;	/* address in network order */
318*0Sstevel@tonic-gate 	uint64_t if_flags;		/* interface flags */
319*0Sstevel@tonic-gate } if_info_t;
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate static if_info_t *if_info = NULL;	/* if cache, protected by iflock */
322*0Sstevel@tonic-gate static int n_ifs = 0;			/* number of cached interfaces */
323*0Sstevel@tonic-gate static int numifs_last = 0;		/* number of interfaces last seen */
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate /*
326*0Sstevel@tonic-gate  * Builds the interface cache.  Write lock on iflock is needed
327*0Sstevel@tonic-gate  * for calling this routine.  It sets _nderror for error returns.
328*0Sstevel@tonic-gate  * Returns TRUE if successful, FALSE otherwise.
329*0Sstevel@tonic-gate  * Changing the structures ifreq and ifconf to lifreq and lifconf to
330*0Sstevel@tonic-gate  * have larger flag field. This is to accomodate the extra flags associated
331*0Sstevel@tonic-gate  * with the interface. Also introducing lifn which will contain the number
332*0Sstevel@tonic-gate  * of IPV4 interfaces present.
333*0Sstevel@tonic-gate  */
334*0Sstevel@tonic-gate static bool_t
335*0Sstevel@tonic-gate get_if_info()
336*0Sstevel@tonic-gate {
337*0Sstevel@tonic-gate 	size_t		needed;
338*0Sstevel@tonic-gate 	struct lifreq	*buf = NULL;
339*0Sstevel@tonic-gate 	int		numifs;
340*0Sstevel@tonic-gate 	struct lifconf  lifc;
341*0Sstevel@tonic-gate 	struct lifreq   *lifr;
342*0Sstevel@tonic-gate 	struct lifnum   lifn;
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	lifn.lifn_family = AF_INET;
345*0Sstevel@tonic-gate 	lifn.lifn_flags = 0;
346*0Sstevel@tonic-gate getifnum:
347*0Sstevel@tonic-gate 	if (nss_ioctl(AF_INET, SIOCGLIFNUM, &lifn) == -1) {
348*0Sstevel@tonic-gate 		numifs = MAXIFS;
349*0Sstevel@tonic-gate 	} else {
350*0Sstevel@tonic-gate 		numifs = lifn.lifn_count;
351*0Sstevel@tonic-gate 	}
352*0Sstevel@tonic-gate 	/*
353*0Sstevel@tonic-gate 	 * Add a small fudge factor in case interfaces are plumbed
354*0Sstevel@tonic-gate 	 * between the SIOCGLIFNUM and SIOCGLIFCONF.
355*0Sstevel@tonic-gate 	 */
356*0Sstevel@tonic-gate 	needed = (numifs + 4) * sizeof (struct lifreq);
357*0Sstevel@tonic-gate 	if (buf == NULL)
358*0Sstevel@tonic-gate 		buf = malloc(needed);
359*0Sstevel@tonic-gate 	else
360*0Sstevel@tonic-gate 		buf = realloc(buf, needed);
361*0Sstevel@tonic-gate 	if (buf == NULL) {
362*0Sstevel@tonic-gate 		_nderror = ND_NOMEM;
363*0Sstevel@tonic-gate 		return (FALSE);
364*0Sstevel@tonic-gate 	}
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	lifc.lifc_family = AF_INET;
367*0Sstevel@tonic-gate 	lifc.lifc_flags = 0;
368*0Sstevel@tonic-gate 	lifc.lifc_len = needed;
369*0Sstevel@tonic-gate 	lifc.lifc_buf = (char *)buf;
370*0Sstevel@tonic-gate 	if (nss_ioctl(AF_INET, SIOCGLIFCONF, &lifc) == -1) {
371*0Sstevel@tonic-gate 		/*
372*0Sstevel@tonic-gate 		 * IP returns EINVAL if the buffer was too small to fit
373*0Sstevel@tonic-gate 		 * all of the entries.  If that's the case, go back and
374*0Sstevel@tonic-gate 		 * try again.
375*0Sstevel@tonic-gate 		 */
376*0Sstevel@tonic-gate 		if (errno == EINVAL)
377*0Sstevel@tonic-gate 			goto getifnum;
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 		free(buf);
380*0Sstevel@tonic-gate 		free(if_info);
381*0Sstevel@tonic-gate 		if_info = NULL;
382*0Sstevel@tonic-gate 		_nderror = ND_SYSTEM;
383*0Sstevel@tonic-gate 		return (FALSE);
384*0Sstevel@tonic-gate 	}
385*0Sstevel@tonic-gate 	numifs = lifc.lifc_len / (int)sizeof (struct lifreq);
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	if (if_info == NULL || numifs > numifs_last) {
388*0Sstevel@tonic-gate 		if (if_info == NULL)
389*0Sstevel@tonic-gate 			if_info = malloc(numifs * sizeof (if_info_t));
390*0Sstevel@tonic-gate 		else
391*0Sstevel@tonic-gate 			if_info = realloc(if_info, numifs * sizeof (if_info_t));
392*0Sstevel@tonic-gate 		if (if_info == NULL) {
393*0Sstevel@tonic-gate 			free(buf);
394*0Sstevel@tonic-gate 			_nderror = ND_NOMEM;
395*0Sstevel@tonic-gate 			return (FALSE);
396*0Sstevel@tonic-gate 		}
397*0Sstevel@tonic-gate 		numifs_last = numifs;
398*0Sstevel@tonic-gate 	}
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	n_ifs = 0;
401*0Sstevel@tonic-gate 	for (lifr = buf; lifr < (buf + numifs); lifr++) {
402*0Sstevel@tonic-gate 		if (lifr->lifr_addr.ss_family != AF_INET)
403*0Sstevel@tonic-gate 			continue;
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 		if_info[n_ifs].if_address =
406*0Sstevel@tonic-gate 			((struct sockaddr_in *)&lifr->lifr_addr)->sin_addr;
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 		if (nss_ioctl(AF_INET, SIOCGLIFFLAGS, lifr) < 0)
409*0Sstevel@tonic-gate 			continue;
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 		if ((lifr->lifr_flags & IFF_UP) == 0)
412*0Sstevel@tonic-gate 			continue;
413*0Sstevel@tonic-gate 		if_info[n_ifs].if_flags = lifr->lifr_flags;
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 		if (nss_ioctl(AF_INET, SIOCGLIFNETMASK, lifr) < 0)
416*0Sstevel@tonic-gate 			continue;
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 		if_info[n_ifs].if_netmask =
419*0Sstevel@tonic-gate 			((struct sockaddr_in *)&lifr->lifr_addr)->sin_addr;
420*0Sstevel@tonic-gate 		n_ifs++;
421*0Sstevel@tonic-gate 	}
422*0Sstevel@tonic-gate 	free(buf);
423*0Sstevel@tonic-gate 	return (TRUE);
424*0Sstevel@tonic-gate }
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate /*
428*0Sstevel@tonic-gate  * Update the interface cache based on last update time.
429*0Sstevel@tonic-gate  */
430*0Sstevel@tonic-gate static bool_t
431*0Sstevel@tonic-gate update_if_cache()
432*0Sstevel@tonic-gate {
433*0Sstevel@tonic-gate 	time_t	curtime;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	(void) rw_wrlock(&iflock);
436*0Sstevel@tonic-gate 	/*
437*0Sstevel@tonic-gate 	 * Check if some other thread has beaten this one to it.
438*0Sstevel@tonic-gate 	 */
439*0Sstevel@tonic-gate 	(void) time(&curtime);
440*0Sstevel@tonic-gate 	if ((curtime - last_updated) >= if_cache_refresh_time) {
441*0Sstevel@tonic-gate 		if (!get_if_info()) {
442*0Sstevel@tonic-gate 			(void) rw_unlock(&iflock);
443*0Sstevel@tonic-gate 			return (FALSE);
444*0Sstevel@tonic-gate 		}
445*0Sstevel@tonic-gate 		(void) time(&last_updated);
446*0Sstevel@tonic-gate 	}
447*0Sstevel@tonic-gate 	(void) rw_unlock(&iflock);
448*0Sstevel@tonic-gate 	return (TRUE);
449*0Sstevel@tonic-gate }
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate /*
453*0Sstevel@tonic-gate  * Given an IP address, check if this matches any of the interface
454*0Sstevel@tonic-gate  * addresses.  If an error occurs, return FALSE so that the caller
455*0Sstevel@tonic-gate  * will not assume that this address belongs to this machine.
456*0Sstevel@tonic-gate  */
457*0Sstevel@tonic-gate static bool_t
458*0Sstevel@tonic-gate is_my_address(addr)
459*0Sstevel@tonic-gate 	struct in_addr addr;		/* address in network order */
460*0Sstevel@tonic-gate {
461*0Sstevel@tonic-gate 	time_t		curtime;
462*0Sstevel@tonic-gate 	if_info_t	*ifn;
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 	(void) time(&curtime);
465*0Sstevel@tonic-gate 	if ((curtime - last_updated) >= if_cache_refresh_time) {
466*0Sstevel@tonic-gate 		/*
467*0Sstevel@tonic-gate 		 * Cache needs to be refreshed.
468*0Sstevel@tonic-gate 		 */
469*0Sstevel@tonic-gate 		if (!update_if_cache())
470*0Sstevel@tonic-gate 			return (FALSE);
471*0Sstevel@tonic-gate 	}
472*0Sstevel@tonic-gate 	(void) rw_rdlock(&iflock);
473*0Sstevel@tonic-gate 	for (ifn = if_info; ifn < (if_info + n_ifs); ifn++) {
474*0Sstevel@tonic-gate 		if (addr.s_addr == ifn->if_address.s_addr) {
475*0Sstevel@tonic-gate 			(void) rw_unlock(&iflock);
476*0Sstevel@tonic-gate 			return (TRUE);
477*0Sstevel@tonic-gate 		}
478*0Sstevel@tonic-gate 	}
479*0Sstevel@tonic-gate 	(void) rw_unlock(&iflock);
480*0Sstevel@tonic-gate 	return (FALSE);
481*0Sstevel@tonic-gate }
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate /*
485*0Sstevel@tonic-gate  * Given a host name, check if it is this host.
486*0Sstevel@tonic-gate  */
487*0Sstevel@tonic-gate bool_t
488*0Sstevel@tonic-gate __inet_netdir_is_my_host(host)
489*0Sstevel@tonic-gate 	char		*host;
490*0Sstevel@tonic-gate {
491*0Sstevel@tonic-gate 	int		error;
492*0Sstevel@tonic-gate 	char		buf[NSS_BUFLEN_HOSTS];
493*0Sstevel@tonic-gate 	struct hostent	res, *h;
494*0Sstevel@tonic-gate 	char		**c;
495*0Sstevel@tonic-gate 	struct in_addr	in;
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 	h = gethostbyname_r(host, (void *)&res, buf, sizeof (buf), &error);
498*0Sstevel@tonic-gate 	if (h == NULL)
499*0Sstevel@tonic-gate 		return (FALSE);
500*0Sstevel@tonic-gate 	if (h->h_addrtype != AF_INET)
501*0Sstevel@tonic-gate 		return (FALSE);
502*0Sstevel@tonic-gate 	for (c = h->h_addr_list; *c != NULL; c++) {
503*0Sstevel@tonic-gate 		(void) memcpy((char *)&in.s_addr, *c, sizeof (in.s_addr));
504*0Sstevel@tonic-gate 		if (is_my_address(in))
505*0Sstevel@tonic-gate 			return (TRUE);
506*0Sstevel@tonic-gate 	}
507*0Sstevel@tonic-gate 	return (FALSE);
508*0Sstevel@tonic-gate }
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate /*
512*0Sstevel@tonic-gate  * Given an IP address, find the interface address that has the best
513*0Sstevel@tonic-gate  * prefix match.  Return the address in network order.
514*0Sstevel@tonic-gate  */
515*0Sstevel@tonic-gate static uint32_t
516*0Sstevel@tonic-gate get_best_match(addr)
517*0Sstevel@tonic-gate 	struct in_addr addr;
518*0Sstevel@tonic-gate {
519*0Sstevel@tonic-gate 	if_info_t *bestmatch, *ifn;
520*0Sstevel@tonic-gate 	int bestcount, count, limit;
521*0Sstevel@tonic-gate 	uint32_t mask, netmask, clnt_addr, if_addr;
522*0Sstevel@tonic-gate 	bool_t found, subnet_match;
523*0Sstevel@tonic-gate 	int subnet_count;
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 	bestmatch = NULL;				/* no match yet */
526*0Sstevel@tonic-gate 	bestcount = BITSPERBYTE * sizeof (uint32_t);	/* worst match */
527*0Sstevel@tonic-gate 	clnt_addr = ntohl(addr.s_addr);			/* host order */
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 	subnet_match = FALSE;		/* subnet match not found yet */
530*0Sstevel@tonic-gate 	subnet_count = bestcount;	/* worst subnet match */
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 	for (ifn = if_info; ifn < (if_info + n_ifs); ifn++) {
533*0Sstevel@tonic-gate 		netmask = ntohl(ifn->if_netmask.s_addr);  /* host order */
534*0Sstevel@tonic-gate 		if_addr = ntohl(ifn->if_address.s_addr);  /* host order */
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate 		/*
537*0Sstevel@tonic-gate 		 * Checking if the interface selected is FAILED or DEPRECATED.
538*0Sstevel@tonic-gate 		 * In case IFF_FAILED or IFF_DEPRECATED flag for the interface
539*0Sstevel@tonic-gate 		 * is set, we move on to the next interface in the list.
540*0Sstevel@tonic-gate 		 * Refer IPMP(IP Multi Pathing) for more details.
541*0Sstevel@tonic-gate 		 */
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate 		if ((ifn->if_flags & (IFF_FAILED | IFF_DEPRECATED)) != 0)
544*0Sstevel@tonic-gate 			continue;
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 		/*
547*0Sstevel@tonic-gate 		 * set initial count to first bit set in netmask, with
548*0Sstevel@tonic-gate 		 * zero being the number of the least significant bit.
549*0Sstevel@tonic-gate 		 */
550*0Sstevel@tonic-gate 		for (count = 0, mask = netmask; mask && ((mask & 1) == 0);
551*0Sstevel@tonic-gate 						count++, mask >>= 1);
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 		/*
554*0Sstevel@tonic-gate 		 * Set limit so that we don't try to match prefixes shorter
555*0Sstevel@tonic-gate 		 * than the inherent netmask for the class (A, B, C, etc).
556*0Sstevel@tonic-gate 		 */
557*0Sstevel@tonic-gate 		if (IN_CLASSC(if_addr))
558*0Sstevel@tonic-gate 			limit = IN_CLASSC_NSHIFT;
559*0Sstevel@tonic-gate 		else if (IN_CLASSB(if_addr))
560*0Sstevel@tonic-gate 			limit = IN_CLASSB_NSHIFT;
561*0Sstevel@tonic-gate 		else if (IN_CLASSA(if_addr))
562*0Sstevel@tonic-gate 			limit = IN_CLASSA_NSHIFT;
563*0Sstevel@tonic-gate 		else
564*0Sstevel@tonic-gate 			limit = 0;
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 		/*
567*0Sstevel@tonic-gate 		 * We assume that the netmask consists of a contiguous
568*0Sstevel@tonic-gate 		 * sequence of 1-bits starting with the most significant bit.
569*0Sstevel@tonic-gate 		 * Prefix comparison starts at the subnet mask level.
570*0Sstevel@tonic-gate 		 * The prefix mask used for comparison is progressively
571*0Sstevel@tonic-gate 		 * reduced until it equals the inherent mask for the
572*0Sstevel@tonic-gate 		 * interface address class.  The algorithm finds an
573*0Sstevel@tonic-gate 		 * interface in the following order of preference:
574*0Sstevel@tonic-gate 		 *
575*0Sstevel@tonic-gate 		 * (1) the longest subnet match
576*0Sstevel@tonic-gate 		 * (2) the best partial subnet match
577*0Sstevel@tonic-gate 		 * (3) the first non-loopback && non-PPP interface
578*0Sstevel@tonic-gate 		 * (4) the first non-loopback interface (PPP is OK)
579*0Sstevel@tonic-gate 		 *
580*0Sstevel@tonic-gate 		 * While checking for condition (3) and (4), we also look
581*0Sstevel@tonic-gate 		 * if the interface we are returning is neither FAILED
582*0Sstevel@tonic-gate 		 * nor DEPRECATED. In case there are no interface
583*0Sstevel@tonic-gate 		 * available, which are neither FAILED nor DEPRECRATED,
584*0Sstevel@tonic-gate 		 * we return 0.
585*0Sstevel@tonic-gate 		 */
586*0Sstevel@tonic-gate 		found = FALSE;
587*0Sstevel@tonic-gate 		while (netmask && count < subnet_count) {
588*0Sstevel@tonic-gate 			if ((netmask & clnt_addr) == (netmask & if_addr)) {
589*0Sstevel@tonic-gate 				bestcount = count;
590*0Sstevel@tonic-gate 				bestmatch = ifn;
591*0Sstevel@tonic-gate 				found = TRUE;
592*0Sstevel@tonic-gate 				break;
593*0Sstevel@tonic-gate 			}
594*0Sstevel@tonic-gate 			netmask <<= 1;
595*0Sstevel@tonic-gate 			count++;
596*0Sstevel@tonic-gate 			if (count >= bestcount || count > limit || subnet_match)
597*0Sstevel@tonic-gate 				break;
598*0Sstevel@tonic-gate 		}
599*0Sstevel@tonic-gate 		/*
600*0Sstevel@tonic-gate 		 * If a subnet level match occurred, note this for
601*0Sstevel@tonic-gate 		 * comparison with future subnet matches.
602*0Sstevel@tonic-gate 		 */
603*0Sstevel@tonic-gate 		if (found && (netmask == ntohl(ifn->if_netmask.s_addr))) {
604*0Sstevel@tonic-gate 			subnet_match = TRUE;
605*0Sstevel@tonic-gate 			subnet_count = count;
606*0Sstevel@tonic-gate 		}
607*0Sstevel@tonic-gate 	}
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate 	/*
610*0Sstevel@tonic-gate 	 * If we don't have a match, select the first interface that
611*0Sstevel@tonic-gate 	 * is not a loopback interface (and preferably not a PPP interface)
612*0Sstevel@tonic-gate 	 * as the best match.
613*0Sstevel@tonic-gate 	 */
614*0Sstevel@tonic-gate 	if (bestmatch == NULL) {
615*0Sstevel@tonic-gate 		for (ifn = if_info; ifn < (if_info + n_ifs); ifn++) {
616*0Sstevel@tonic-gate 			if ((ifn->if_flags & (IFF_LOOPBACK |
617*0Sstevel@tonic-gate 				IFF_FAILED | IFF_DEPRECATED)) == 0) {
618*0Sstevel@tonic-gate 				bestmatch = ifn;
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 				/*
621*0Sstevel@tonic-gate 				 * If this isn't a PPP interface, we're
622*0Sstevel@tonic-gate 				 * done.  Otherwise, keep walking through
623*0Sstevel@tonic-gate 				 * the list in case we have a non-loopback
624*0Sstevel@tonic-gate 				 * iface that ISN'T a PPP further down our
625*0Sstevel@tonic-gate 				 * list...
626*0Sstevel@tonic-gate 				 */
627*0Sstevel@tonic-gate 				if ((ifn->if_flags & IFF_POINTOPOINT) == 0) {
628*0Sstevel@tonic-gate #ifdef DEBUG
629*0Sstevel@tonic-gate 		(void) printf("found !loopback && !non-PPP interface: %s\n",
630*0Sstevel@tonic-gate 				inet_ntoa(ifn->if_address));
631*0Sstevel@tonic-gate #endif
632*0Sstevel@tonic-gate 					break;
633*0Sstevel@tonic-gate 				}
634*0Sstevel@tonic-gate 			}
635*0Sstevel@tonic-gate 		}
636*0Sstevel@tonic-gate 	}
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	if (bestmatch != NULL)
639*0Sstevel@tonic-gate 		return (bestmatch->if_address.s_addr);
640*0Sstevel@tonic-gate 	else
641*0Sstevel@tonic-gate 		return (0);
642*0Sstevel@tonic-gate }
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate static int
645*0Sstevel@tonic-gate is_myself(struct sockaddr_in6 *sa6)
646*0Sstevel@tonic-gate {
647*0Sstevel@tonic-gate 	struct sioc_addrreq areq;
648*0Sstevel@tonic-gate 	int s;
649*0Sstevel@tonic-gate 
650*0Sstevel@tonic-gate 	if ((s = open("/dev/udp6", O_RDONLY)) < 0) {
651*0Sstevel@tonic-gate 		syslog(LOG_ERR, "is_myself: can't open /dev/udp6: %m");
652*0Sstevel@tonic-gate 		return (0);
653*0Sstevel@tonic-gate 	}
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate 	memcpy(&areq.sa_addr, (struct sockaddr_storage *)sa6,
656*0Sstevel@tonic-gate 		sizeof (struct sockaddr_storage));
657*0Sstevel@tonic-gate 	areq.sa_res = -1;
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	if (ioctl(s, SIOCTMYADDR, (caddr_t)&areq) < 0) {
660*0Sstevel@tonic-gate 		syslog(LOG_ERR, "is_myself:SIOCTMYADDR failed: %m");
661*0Sstevel@tonic-gate 		close(s);
662*0Sstevel@tonic-gate 		return (0);
663*0Sstevel@tonic-gate 	}
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	close(s);
666*0Sstevel@tonic-gate 	return (areq.sa_res);
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate }
669*0Sstevel@tonic-gate /*
670*0Sstevel@tonic-gate  * For a given destination address, determine a source address to use.
671*0Sstevel@tonic-gate  * Returns wildcard address if it cannot determine the source address.
672*0Sstevel@tonic-gate  * copied from ping.c.
673*0Sstevel@tonic-gate  */
674*0Sstevel@tonic-gate union any_in_addr {
675*0Sstevel@tonic-gate 	struct in6_addr addr6;
676*0Sstevel@tonic-gate 	struct in_addr addr;
677*0Sstevel@tonic-gate };
678*0Sstevel@tonic-gate static bool_t
679*0Sstevel@tonic-gate select_server_addr(union any_in_addr *dst_addr, int family,
680*0Sstevel@tonic-gate     union any_in_addr *src_addr)
681*0Sstevel@tonic-gate {
682*0Sstevel@tonic-gate 	struct sockaddr *sock;
683*0Sstevel@tonic-gate 	struct sockaddr_in *sin;
684*0Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
685*0Sstevel@tonic-gate 	int tmp_fd;
686*0Sstevel@tonic-gate 	size_t sock_len;
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 	sock = calloc(1, sizeof (struct sockaddr_in6));
689*0Sstevel@tonic-gate 	if (sock == NULL) {
690*0Sstevel@tonic-gate 		return (FALSE);
691*0Sstevel@tonic-gate 	}
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 	if (family == AF_INET) {
694*0Sstevel@tonic-gate 		sin = (struct sockaddr_in *)sock;
695*0Sstevel@tonic-gate 		sin->sin_family = AF_INET;
696*0Sstevel@tonic-gate 		sin->sin_port = 111;
697*0Sstevel@tonic-gate 		sin->sin_addr = dst_addr->addr;
698*0Sstevel@tonic-gate 		sock_len = sizeof (struct sockaddr_in);
699*0Sstevel@tonic-gate 	} else {
700*0Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)sock;
701*0Sstevel@tonic-gate 		sin6->sin6_family = AF_INET6;
702*0Sstevel@tonic-gate 		sin6->sin6_port = 111;
703*0Sstevel@tonic-gate 		sin6->sin6_addr = dst_addr->addr6;
704*0Sstevel@tonic-gate 		sock_len = sizeof (struct sockaddr_in6);
705*0Sstevel@tonic-gate 	}
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 	/* open a UDP socket */
708*0Sstevel@tonic-gate 	if ((tmp_fd = _so_socket(family, SOCK_DGRAM, 0,
709*0Sstevel@tonic-gate 		NULL, SOV_SOCKBSD)) < 0) {
710*0Sstevel@tonic-gate 		syslog(LOG_ERR, "selsect_server_addr:connect failed\n");
711*0Sstevel@tonic-gate 		return (FALSE);
712*0Sstevel@tonic-gate 	}
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 	/* connect it */
715*0Sstevel@tonic-gate 	if (_so_connect(tmp_fd, sock, sock_len, SOV_SOCKBSD) < 0) {
716*0Sstevel@tonic-gate 		/*
717*0Sstevel@tonic-gate 		 * If there's no route to the destination, this connect() call
718*0Sstevel@tonic-gate 		 * fails. We just return all-zero (wildcard) as the source
719*0Sstevel@tonic-gate 		 * address, so that user can get to see "no route to dest"
720*0Sstevel@tonic-gate 		 * message, as it'll try to send the probe packet out and will
721*0Sstevel@tonic-gate 		 * receive ICMP unreachable.
722*0Sstevel@tonic-gate 		 */
723*0Sstevel@tonic-gate 		if (family == AF_INET)
724*0Sstevel@tonic-gate 			src_addr->addr.s_addr = INADDR_ANY;
725*0Sstevel@tonic-gate 		else
726*0Sstevel@tonic-gate 			/*
727*0Sstevel@tonic-gate 			 * Since in6addr_any is not in the scope
728*0Sstevel@tonic-gate 			 * use the following hack
729*0Sstevel@tonic-gate 			 */
730*0Sstevel@tonic-gate 			memset(src_addr->addr6.s6_addr,
731*0Sstevel@tonic-gate 				0, sizeof (struct in6_addr));
732*0Sstevel@tonic-gate 		(void) close(tmp_fd);
733*0Sstevel@tonic-gate 		free(sock);
734*0Sstevel@tonic-gate 		return (FALSE);
735*0Sstevel@tonic-gate 	}
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 	/* get the local sock info */
738*0Sstevel@tonic-gate 	if (_so_getsockname(tmp_fd, sock, &sock_len, SOV_DEFAULT) < 0) {
739*0Sstevel@tonic-gate 		syslog(LOG_ERR, "selsect_server_addr:getsockname failed\n");
740*0Sstevel@tonic-gate 		(void) close(tmp_fd);
741*0Sstevel@tonic-gate 		free(sock);
742*0Sstevel@tonic-gate 		return (FALSE);
743*0Sstevel@tonic-gate 	}
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	if (family == AF_INET) {
746*0Sstevel@tonic-gate 		sin = (struct sockaddr_in *)sock;
747*0Sstevel@tonic-gate 		src_addr->addr = sin->sin_addr;
748*0Sstevel@tonic-gate 	} else {
749*0Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)sock;
750*0Sstevel@tonic-gate 		src_addr->addr6 = sin6->sin6_addr;
751*0Sstevel@tonic-gate 	}
752*0Sstevel@tonic-gate 
753*0Sstevel@tonic-gate 	(void) close(tmp_fd);
754*0Sstevel@tonic-gate 	free(sock);
755*0Sstevel@tonic-gate 	return (TRUE);
756*0Sstevel@tonic-gate }
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate /*
759*0Sstevel@tonic-gate  * This internal routine will merge one of those "universal" addresses
760*0Sstevel@tonic-gate  * to the one which will make sense to the remote caller.
761*0Sstevel@tonic-gate  */
762*0Sstevel@tonic-gate static char *
763*0Sstevel@tonic-gate inet_netdir_mergeaddr(tp, ruaddr, uaddr)
764*0Sstevel@tonic-gate 	struct netconfig	*tp;	/* the transport provider */
765*0Sstevel@tonic-gate 	char			*ruaddr; /* remote uaddr of the caller */
766*0Sstevel@tonic-gate 	char			*uaddr;	/* the address */
767*0Sstevel@tonic-gate {
768*0Sstevel@tonic-gate 	char	tmp[SYS_NMLN], *cp;
769*0Sstevel@tonic-gate 	int	j;
770*0Sstevel@tonic-gate 	struct	in_addr clientaddr, bestmatch;
771*0Sstevel@tonic-gate 	time_t	curtime;
772*0Sstevel@tonic-gate 	int af;
773*0Sstevel@tonic-gate 
774*0Sstevel@tonic-gate 	if (!uaddr || !ruaddr || !tp) {
775*0Sstevel@tonic-gate 		_nderror = ND_BADARG;
776*0Sstevel@tonic-gate 		return (NULL);
777*0Sstevel@tonic-gate 	}
778*0Sstevel@tonic-gate 	(void) bzero(tmp, SYS_NMLN);
779*0Sstevel@tonic-gate 
780*0Sstevel@tonic-gate 	if (strcmp(tp->nc_protofmly, NC_INET) == 0)
781*0Sstevel@tonic-gate 		af = AF_INET;
782*0Sstevel@tonic-gate 	else
783*0Sstevel@tonic-gate 		af = AF_INET6;
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate 	if (af == AF_INET) {
786*0Sstevel@tonic-gate 		if (strncmp(ruaddr, "0.0.0.0.", strlen("0.0.0.0.")) == 0)
787*0Sstevel@tonic-gate 			/* thats me: return the way it is */
788*0Sstevel@tonic-gate 			return (strdup(uaddr));
789*0Sstevel@tonic-gate 
790*0Sstevel@tonic-gate 		/*
791*0Sstevel@tonic-gate 		 * Convert remote uaddr into an in_addr so that we can compare
792*0Sstevel@tonic-gate 		 * to it.  Shave off last two dotted-decimal values.
793*0Sstevel@tonic-gate 		 */
794*0Sstevel@tonic-gate 		for (cp = ruaddr, j = 0; j < 4; j++, cp++)
795*0Sstevel@tonic-gate 			if ((cp = strchr(cp, '.')) == NULL)
796*0Sstevel@tonic-gate 				break;
797*0Sstevel@tonic-gate 
798*0Sstevel@tonic-gate 		if (cp != NULL)
799*0Sstevel@tonic-gate 			*--cp = '\0';	/* null out the dot after the IP addr */
800*0Sstevel@tonic-gate 		else {
801*0Sstevel@tonic-gate 			_nderror = ND_NOHOST;
802*0Sstevel@tonic-gate 			return (NULL);
803*0Sstevel@tonic-gate 		}
804*0Sstevel@tonic-gate 
805*0Sstevel@tonic-gate 		clientaddr.s_addr = inet_addr(ruaddr);
806*0Sstevel@tonic-gate 
807*0Sstevel@tonic-gate #ifdef DEBUG
808*0Sstevel@tonic-gate 		(void) printf("client's address is %s and %s\n",
809*0Sstevel@tonic-gate 			ruaddr, inet_ntoa(clientaddr));
810*0Sstevel@tonic-gate #endif
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 		/* We know cp is not NULL due to the check above */
813*0Sstevel@tonic-gate 		*cp = '.';	/* Put the dot back in the IP addr */
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 		(void) time(&curtime);
816*0Sstevel@tonic-gate 		if ((curtime - last_updated) >= if_cache_refresh_time) {
817*0Sstevel@tonic-gate 			/*
818*0Sstevel@tonic-gate 			 * Cache needs to be refreshed.
819*0Sstevel@tonic-gate 			 */
820*0Sstevel@tonic-gate 			if (!update_if_cache())
821*0Sstevel@tonic-gate 				return (NULL);
822*0Sstevel@tonic-gate 		}
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate 		/*
825*0Sstevel@tonic-gate 		 * Find the best match now.
826*0Sstevel@tonic-gate 		 */
827*0Sstevel@tonic-gate 		(void) rw_rdlock(&iflock);
828*0Sstevel@tonic-gate 		bestmatch.s_addr = get_best_match(clientaddr);
829*0Sstevel@tonic-gate 		(void) rw_unlock(&iflock);
830*0Sstevel@tonic-gate 
831*0Sstevel@tonic-gate 		if (bestmatch.s_addr)
832*0Sstevel@tonic-gate 			_nderror = ND_OK;
833*0Sstevel@tonic-gate 		else {
834*0Sstevel@tonic-gate 			_nderror = ND_NOHOST;
835*0Sstevel@tonic-gate 			return (NULL);
836*0Sstevel@tonic-gate 		}
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate 		/* prepare the reply */
839*0Sstevel@tonic-gate 		(void) memset(tmp, '\0', sizeof (tmp));
840*0Sstevel@tonic-gate 
841*0Sstevel@tonic-gate 		/* reply consists of the IP addr of the closest interface */
842*0Sstevel@tonic-gate 		(void) strcpy(tmp, inet_ntoa(bestmatch));
843*0Sstevel@tonic-gate 
844*0Sstevel@tonic-gate 		/*
845*0Sstevel@tonic-gate 		 * ... and the port number part (last two dotted-decimal values)
846*0Sstevel@tonic-gate 		 * of uaddr
847*0Sstevel@tonic-gate 		 */
848*0Sstevel@tonic-gate 		for (cp = uaddr, j = 0; j < 4; j++, cp++)
849*0Sstevel@tonic-gate 			cp = strchr(cp, '.');
850*0Sstevel@tonic-gate 		(void) strcat(tmp, --cp);
851*0Sstevel@tonic-gate 
852*0Sstevel@tonic-gate 	} else {
853*0Sstevel@tonic-gate 		/* IPv6 */
854*0Sstevel@tonic-gate 		char *dot;
855*0Sstevel@tonic-gate 		char *truaddr;
856*0Sstevel@tonic-gate 		char  name2[SYS_NMLN];
857*0Sstevel@tonic-gate 		struct sockaddr_in6 sa;
858*0Sstevel@tonic-gate 		struct sockaddr_in6 server_addr;
859*0Sstevel@tonic-gate 		union any_in_addr in_addr, out_addr;
860*0Sstevel@tonic-gate 
861*0Sstevel@tonic-gate 		if (strncmp(ruaddr, "::", strlen("::")) == 0)
862*0Sstevel@tonic-gate 			if (*(ruaddr + strlen("::")) == '\0')
863*0Sstevel@tonic-gate 				/* thats me: return the way it is */
864*0Sstevel@tonic-gate 				return (strdup(uaddr));
865*0Sstevel@tonic-gate 
866*0Sstevel@tonic-gate 		bzero(&sa, sizeof (sa));
867*0Sstevel@tonic-gate 		bzero(&server_addr, sizeof (server_addr));
868*0Sstevel@tonic-gate 		truaddr = &tmp[0];
869*0Sstevel@tonic-gate 		strcpy(truaddr, ruaddr);
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 		/*
872*0Sstevel@tonic-gate 		 * now extract the server ip address from
873*0Sstevel@tonic-gate 		 * the address supplied by client.  It can be
874*0Sstevel@tonic-gate 		 * client's own IP address.
875*0Sstevel@tonic-gate 		 */
876*0Sstevel@tonic-gate 
877*0Sstevel@tonic-gate 		if ((dot = strrchr(truaddr, '.')) != 0) {
878*0Sstevel@tonic-gate 			*dot = '\0';
879*0Sstevel@tonic-gate 			if ((dot = strrchr(truaddr, '.')) != 0)
880*0Sstevel@tonic-gate 				*dot = '\0';
881*0Sstevel@tonic-gate 		}
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 		if (dot == 0) {
884*0Sstevel@tonic-gate 			_nderror = ND_NOHOST;
885*0Sstevel@tonic-gate 			return (NULL);
886*0Sstevel@tonic-gate 		}
887*0Sstevel@tonic-gate 
888*0Sstevel@tonic-gate 		if (inet_pton(af, truaddr, sa.sin6_addr.s6_addr)
889*0Sstevel@tonic-gate 		    != 1) {
890*0Sstevel@tonic-gate 			_nderror = ND_NOHOST;
891*0Sstevel@tonic-gate 			return (NULL);
892*0Sstevel@tonic-gate 		}
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 		in_addr.addr6 = sa.sin6_addr;
895*0Sstevel@tonic-gate 		sa.sin6_family = AF_INET6;
896*0Sstevel@tonic-gate 
897*0Sstevel@tonic-gate 		/* is it my IP address */
898*0Sstevel@tonic-gate 		if (!is_myself(&sa)) {
899*0Sstevel@tonic-gate 			/* have the kernel select one for me */
900*0Sstevel@tonic-gate 			if (select_server_addr(&in_addr, af, &out_addr) ==
901*0Sstevel@tonic-gate 			    FALSE)
902*0Sstevel@tonic-gate 				return (NULL);
903*0Sstevel@tonic-gate 			server_addr.sin6_addr = out_addr.addr6;
904*0Sstevel@tonic-gate 		}
905*0Sstevel@tonic-gate 		else
906*0Sstevel@tonic-gate 			memcpy((char *)&server_addr, (char *)&sa,
907*0Sstevel@tonic-gate 				sizeof (struct sockaddr_in6));
908*0Sstevel@tonic-gate #ifdef DEBUG
909*0Sstevel@tonic-gate 		printf("%s\n", inet_ntop(af, out_addr.addr6.s6_addr,
910*0Sstevel@tonic-gate 			tmp, sizeof (tmp)));
911*0Sstevel@tonic-gate #endif
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate 		if (inet_ntop(af, server_addr.sin6_addr.s6_addr,
914*0Sstevel@tonic-gate 			tmp, sizeof (tmp)) == NULL) {
915*0Sstevel@tonic-gate 			_nderror = ND_NOHOST;
916*0Sstevel@tonic-gate 			return (NULL);
917*0Sstevel@tonic-gate 		}
918*0Sstevel@tonic-gate 
919*0Sstevel@tonic-gate 		/* now extract the port info */
920*0Sstevel@tonic-gate 		if ((dot = strrchr(uaddr, '.')) != 0) {
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate 			char *p;
923*0Sstevel@tonic-gate 
924*0Sstevel@tonic-gate 			p = --dot;
925*0Sstevel@tonic-gate 			while (*p-- != '.');
926*0Sstevel@tonic-gate 			p++;
927*0Sstevel@tonic-gate 			strcat(tmp + strlen(tmp), p);
928*0Sstevel@tonic-gate 			_nderror = ND_OK;
929*0Sstevel@tonic-gate 		} else {
930*0Sstevel@tonic-gate 			_nderror = ND_NOHOST;
931*0Sstevel@tonic-gate 			return (NULL);
932*0Sstevel@tonic-gate 		}
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 	}
935*0Sstevel@tonic-gate 	return (strdup(tmp));
936*0Sstevel@tonic-gate }
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate static int
939*0Sstevel@tonic-gate bindresvport(nconf, fd, addr)
940*0Sstevel@tonic-gate 	struct netconfig *nconf;
941*0Sstevel@tonic-gate 	int fd;
942*0Sstevel@tonic-gate 	struct netbuf *addr;
943*0Sstevel@tonic-gate {
944*0Sstevel@tonic-gate 	int res;
945*0Sstevel@tonic-gate 	struct sockaddr_in myaddr;
946*0Sstevel@tonic-gate 	struct sockaddr_in6 myaddr6;
947*0Sstevel@tonic-gate 	struct sockaddr_in *sin;
948*0Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
949*0Sstevel@tonic-gate 	int i;
950*0Sstevel@tonic-gate 	struct t_bind tbindstr, *tres;
951*0Sstevel@tonic-gate 	struct t_info tinfo;
952*0Sstevel@tonic-gate 	struct t_optmgmt req, resp;
953*0Sstevel@tonic-gate 	struct opthdr *opt;
954*0Sstevel@tonic-gate 	int reqbuf[64/sizeof (int)];
955*0Sstevel@tonic-gate 	int *optval;
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate 	union {
958*0Sstevel@tonic-gate 		struct sockaddr_in *sin;
959*0Sstevel@tonic-gate 		struct sockaddr_in6 *sin6;
960*0Sstevel@tonic-gate 		char *buf;
961*0Sstevel@tonic-gate 	} u;
962*0Sstevel@tonic-gate 
963*0Sstevel@tonic-gate 	_nderror = ND_SYSTEM;
964*0Sstevel@tonic-gate 	if (geteuid()) {
965*0Sstevel@tonic-gate 		errno = EACCES;
966*0Sstevel@tonic-gate 		return (-1);
967*0Sstevel@tonic-gate 	}
968*0Sstevel@tonic-gate 	if ((i = t_getstate(fd)) != T_UNBND) {
969*0Sstevel@tonic-gate 		if (t_errno == TBADF)
970*0Sstevel@tonic-gate 			errno = EBADF;
971*0Sstevel@tonic-gate 		if (i != -1)
972*0Sstevel@tonic-gate 			errno = EISCONN;
973*0Sstevel@tonic-gate 		return (-1);
974*0Sstevel@tonic-gate 	}
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate 	if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
977*0Sstevel@tonic-gate 		if (addr == NULL) {
978*0Sstevel@tonic-gate 			sin = &myaddr;
979*0Sstevel@tonic-gate 			(void) memset((char *)sin, 0, sizeof (*sin));
980*0Sstevel@tonic-gate 			sin->sin_family = AF_INET;
981*0Sstevel@tonic-gate 			u.buf = (char *)sin;
982*0Sstevel@tonic-gate 		} else
983*0Sstevel@tonic-gate 			u.buf = (char *)addr->buf;
984*0Sstevel@tonic-gate 	} else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
985*0Sstevel@tonic-gate 		if (addr == NULL) {
986*0Sstevel@tonic-gate 			sin6 = &myaddr6;
987*0Sstevel@tonic-gate 			(void) memset((char *)sin6, 0, sizeof (*sin6));
988*0Sstevel@tonic-gate 			sin6->sin6_family = AF_INET6;
989*0Sstevel@tonic-gate 			u.buf = (char *)sin6;
990*0Sstevel@tonic-gate 		} else
991*0Sstevel@tonic-gate 			u.buf = addr->buf;
992*0Sstevel@tonic-gate 
993*0Sstevel@tonic-gate 	} else {
994*0Sstevel@tonic-gate 		errno = EPFNOSUPPORT;
995*0Sstevel@tonic-gate 		return (-1);
996*0Sstevel@tonic-gate 	}
997*0Sstevel@tonic-gate 
998*0Sstevel@tonic-gate 	/* Transform sockaddr_in to netbuf */
999*0Sstevel@tonic-gate 	if (t_getinfo(fd, &tinfo) == -1)
1000*0Sstevel@tonic-gate 		return (-1);
1001*0Sstevel@tonic-gate 	tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
1002*0Sstevel@tonic-gate 	if (tres == NULL) {
1003*0Sstevel@tonic-gate 		_nderror = ND_NOMEM;
1004*0Sstevel@tonic-gate 		return (-1);
1005*0Sstevel@tonic-gate 	}
1006*0Sstevel@tonic-gate 
1007*0Sstevel@tonic-gate 	tbindstr.qlen = 0; /* Always 0; user should change if he wants to */
1008*0Sstevel@tonic-gate 	tbindstr.addr.buf = (char *)u.buf;
1009*0Sstevel@tonic-gate 	tbindstr.addr.len = tbindstr.addr.maxlen = __rpc_get_a_size(tinfo.addr);
1010*0Sstevel@tonic-gate 
1011*0Sstevel@tonic-gate 	/*
1012*0Sstevel@tonic-gate 	 * Use *_ANONPRIVBIND to ask the kernel to pick a port in the
1013*0Sstevel@tonic-gate 	 * priviledged range for us.
1014*0Sstevel@tonic-gate 	 */
1015*0Sstevel@tonic-gate 	opt = (struct opthdr *)reqbuf;
1016*0Sstevel@tonic-gate 	if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
1017*0Sstevel@tonic-gate 		opt->level = IPPROTO_TCP;
1018*0Sstevel@tonic-gate 		opt->name = TCP_ANONPRIVBIND;
1019*0Sstevel@tonic-gate 	} else if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
1020*0Sstevel@tonic-gate 		opt->level = IPPROTO_UDP;
1021*0Sstevel@tonic-gate 		opt->name = UDP_ANONPRIVBIND;
1022*0Sstevel@tonic-gate 	} else {
1023*0Sstevel@tonic-gate 		errno = EPROTONOSUPPORT;
1024*0Sstevel@tonic-gate 		(void) t_free((char *)tres, T_BIND);
1025*0Sstevel@tonic-gate 		return (-1);
1026*0Sstevel@tonic-gate 	}
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate 	opt->len = sizeof (int);
1029*0Sstevel@tonic-gate 	req.flags = T_NEGOTIATE;
1030*0Sstevel@tonic-gate 	req.opt.len = sizeof (struct opthdr) + opt->len;
1031*0Sstevel@tonic-gate 	req.opt.buf = (char *)opt;
1032*0Sstevel@tonic-gate 	optval = (int *)((char *)reqbuf + sizeof (struct opthdr));
1033*0Sstevel@tonic-gate 	*optval = 1;
1034*0Sstevel@tonic-gate 	resp.flags = 0;
1035*0Sstevel@tonic-gate 	resp.opt.buf = (char *)reqbuf;
1036*0Sstevel@tonic-gate 	resp.opt.maxlen = sizeof (reqbuf);
1037*0Sstevel@tonic-gate 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
1038*0Sstevel@tonic-gate 		(void) t_free((char *)tres, T_BIND);
1039*0Sstevel@tonic-gate 		return (-1);
1040*0Sstevel@tonic-gate 	}
1041*0Sstevel@tonic-gate 
1042*0Sstevel@tonic-gate 	if (u.sin->sin_family == AF_INET)
1043*0Sstevel@tonic-gate 		u.sin->sin_port = htons(0);
1044*0Sstevel@tonic-gate 	else
1045*0Sstevel@tonic-gate 		u.sin6->sin6_port = htons(0);
1046*0Sstevel@tonic-gate 	res = t_bind(fd, &tbindstr, tres);
1047*0Sstevel@tonic-gate 	if (res != 0) {
1048*0Sstevel@tonic-gate 		if (t_errno == TNOADDR) {
1049*0Sstevel@tonic-gate 			_nderror = ND_FAILCTRL;
1050*0Sstevel@tonic-gate 			res = 1;
1051*0Sstevel@tonic-gate 		}
1052*0Sstevel@tonic-gate 	} else {
1053*0Sstevel@tonic-gate 		_nderror = ND_OK;
1054*0Sstevel@tonic-gate 	}
1055*0Sstevel@tonic-gate 
1056*0Sstevel@tonic-gate 	/*
1057*0Sstevel@tonic-gate 	 * Always turn off the option when we are done.  Note that by doing
1058*0Sstevel@tonic-gate 	 * this, if the caller has set this option before calling
1059*0Sstevel@tonic-gate 	 * bindresvport(), it will be unset.  Better be safe...
1060*0Sstevel@tonic-gate 	 */
1061*0Sstevel@tonic-gate 	 *optval = 0;
1062*0Sstevel@tonic-gate 	resp.flags = 0;
1063*0Sstevel@tonic-gate 	resp.opt.buf = (char *)reqbuf;
1064*0Sstevel@tonic-gate 	resp.opt.maxlen = sizeof (reqbuf);
1065*0Sstevel@tonic-gate 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
1066*0Sstevel@tonic-gate 		(void) t_free((char *)tres, T_BIND);
1067*0Sstevel@tonic-gate 		if (res == 0)
1068*0Sstevel@tonic-gate 			(void) t_unbind(fd);
1069*0Sstevel@tonic-gate 		_nderror = ND_FAILCTRL;
1070*0Sstevel@tonic-gate 		return (-1);
1071*0Sstevel@tonic-gate 	}
1072*0Sstevel@tonic-gate 
1073*0Sstevel@tonic-gate 	(void) t_free((char *)tres, T_BIND);
1074*0Sstevel@tonic-gate 	return (res);
1075*0Sstevel@tonic-gate }
1076*0Sstevel@tonic-gate 
1077*0Sstevel@tonic-gate static int
1078*0Sstevel@tonic-gate checkresvport(addr)
1079*0Sstevel@tonic-gate 	struct netbuf *addr;
1080*0Sstevel@tonic-gate {
1081*0Sstevel@tonic-gate 	struct sockaddr_in *sin;
1082*0Sstevel@tonic-gate 	unsigned short port;
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate 	if (addr == NULL) {
1085*0Sstevel@tonic-gate 		_nderror = ND_FAILCTRL;
1086*0Sstevel@tonic-gate 		return (-1);
1087*0Sstevel@tonic-gate 	}
1088*0Sstevel@tonic-gate 	/*
1089*0Sstevel@tonic-gate 	 * Still works for IPv6 since the first two memebers of
1090*0Sstevel@tonic-gate 	 * both address structure point to family and port # respectively
1091*0Sstevel@tonic-gate 	 */
1092*0Sstevel@tonic-gate 	sin = (struct sockaddr_in *)(addr->buf);
1093*0Sstevel@tonic-gate 	port = ntohs(sin->sin_port);
1094*0Sstevel@tonic-gate 	if (port < IPPORT_RESERVED)
1095*0Sstevel@tonic-gate 		return (0);
1096*0Sstevel@tonic-gate 	return (1);
1097*0Sstevel@tonic-gate }
1098