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 1991-2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdio.h>
30*0Sstevel@tonic-gate #include <stdlib.h>
31*0Sstevel@tonic-gate #include <string.h>
32*0Sstevel@tonic-gate #include <unistd.h>
33*0Sstevel@tonic-gate #include <errno.h>
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include <sys/types.h>
36*0Sstevel@tonic-gate #include <sys/stream.h>
37*0Sstevel@tonic-gate #include <sys/stropts.h>
38*0Sstevel@tonic-gate #include <sys/tihdr.h>
39*0Sstevel@tonic-gate #include <sys/tiuser.h>
40*0Sstevel@tonic-gate #include <sys/timod.h>
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate #include <sys/socket.h>
43*0Sstevel@tonic-gate #include <sys/sockio.h>
44*0Sstevel@tonic-gate #include <netinet/in.h>
45*0Sstevel@tonic-gate #include <net/if.h>
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate #include <inet/common.h>
48*0Sstevel@tonic-gate #include <inet/mib2.h>
49*0Sstevel@tonic-gate #include <inet/ip.h>
50*0Sstevel@tonic-gate #include <netinet/igmp_var.h>
51*0Sstevel@tonic-gate #include <netinet/ip_mroute.h>
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate #include <arpa/inet.h>
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate #include <netdb.h>
56*0Sstevel@tonic-gate #include <nss_dbdefs.h>
57*0Sstevel@tonic-gate #include <fcntl.h>
58*0Sstevel@tonic-gate #include <stropts.h>
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate #include "bootparam_private.h"
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate typedef struct mib_item_s {
63*0Sstevel@tonic-gate 	struct mib_item_s	*next_item;
64*0Sstevel@tonic-gate 	long			group;
65*0Sstevel@tonic-gate 	long			mib_id;
66*0Sstevel@tonic-gate 	long			length;
67*0Sstevel@tonic-gate 	char			*valp;
68*0Sstevel@tonic-gate } mib_item_t;
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate static void free_itemlist(mib_item_t *);
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate static mib_item_t *
mibget(int sd)73*0Sstevel@tonic-gate mibget(int sd)
74*0Sstevel@tonic-gate {
75*0Sstevel@tonic-gate 	char			buf[512];
76*0Sstevel@tonic-gate 	int			flags;
77*0Sstevel@tonic-gate 	int			i, j, getcode;
78*0Sstevel@tonic-gate 	struct strbuf		ctlbuf, databuf;
79*0Sstevel@tonic-gate 	struct T_optmgmt_req	*tor = (struct T_optmgmt_req *)(void *)buf;
80*0Sstevel@tonic-gate 	struct T_optmgmt_ack	*toa = (struct T_optmgmt_ack *)(void *)buf;
81*0Sstevel@tonic-gate 	struct T_error_ack	*tea = (struct T_error_ack *)(void *)buf;
82*0Sstevel@tonic-gate 	struct opthdr		*req;
83*0Sstevel@tonic-gate 	mib_item_t		*first_item = nilp(mib_item_t);
84*0Sstevel@tonic-gate 	mib_item_t		*last_item  = nilp(mib_item_t);
85*0Sstevel@tonic-gate 	mib_item_t		*temp;
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
88*0Sstevel@tonic-gate 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
89*0Sstevel@tonic-gate 	tor->OPT_length = sizeof (struct opthdr);
90*0Sstevel@tonic-gate 	tor->MGMT_flags = T_CURRENT;
91*0Sstevel@tonic-gate 	req = (struct opthdr *)&tor[1];
92*0Sstevel@tonic-gate 	req->level = MIB2_IP;		/* any MIB2_xxx value ok here */
93*0Sstevel@tonic-gate 	req->name  = 0;
94*0Sstevel@tonic-gate 	req->len   = 0;
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 	ctlbuf.buf = buf;
97*0Sstevel@tonic-gate 	ctlbuf.len = tor->OPT_length + tor->OPT_offset;
98*0Sstevel@tonic-gate 	flags = 0;
99*0Sstevel@tonic-gate 	if (putmsg(sd, &ctlbuf, nilp(struct strbuf), flags) == -1) {
100*0Sstevel@tonic-gate 		perror("mibget: putmsg(ctl) failed");
101*0Sstevel@tonic-gate 		goto error_exit;
102*0Sstevel@tonic-gate 	}
103*0Sstevel@tonic-gate 	/*
104*0Sstevel@tonic-gate 	 * each reply consists of a ctl part for one fixed structure
105*0Sstevel@tonic-gate 	 * or table, as defined in mib2.h.  The format is a T_OPTMGMT_ACK,
106*0Sstevel@tonic-gate 	 * containing an opthdr structure.  level/name identify the entry,
107*0Sstevel@tonic-gate 	 * len is the size of the data part of the message.
108*0Sstevel@tonic-gate 	 */
109*0Sstevel@tonic-gate 	req = (struct opthdr *)&toa[1];
110*0Sstevel@tonic-gate 	ctlbuf.maxlen = sizeof (buf);
111*0Sstevel@tonic-gate 	for (j = 1; ; j++) {
112*0Sstevel@tonic-gate 		flags = 0;
113*0Sstevel@tonic-gate 		getcode = getmsg(sd, &ctlbuf, nilp(struct strbuf), &flags);
114*0Sstevel@tonic-gate 		if (getcode == -1) {
115*0Sstevel@tonic-gate 			perror("mibget getmsg(ctl) failed");
116*0Sstevel@tonic-gate 			if (debug) {
117*0Sstevel@tonic-gate 				msgout("#   level   name    len");
118*0Sstevel@tonic-gate 				i = 0;
119*0Sstevel@tonic-gate 				for (last_item = first_item; last_item;
120*0Sstevel@tonic-gate 					last_item = last_item->next_item)
121*0Sstevel@tonic-gate 					msgout("%d  %4ld   %5ld   %ld", ++i,
122*0Sstevel@tonic-gate 						last_item->group,
123*0Sstevel@tonic-gate 						last_item->mib_id,
124*0Sstevel@tonic-gate 						last_item->length);
125*0Sstevel@tonic-gate 			}
126*0Sstevel@tonic-gate 			goto error_exit;
127*0Sstevel@tonic-gate 		}
128*0Sstevel@tonic-gate 		if ((getcode == 0) &&
129*0Sstevel@tonic-gate 		    (ctlbuf.len >= sizeof (struct T_optmgmt_ack))&&
130*0Sstevel@tonic-gate 		    (toa->PRIM_type == T_OPTMGMT_ACK) &&
131*0Sstevel@tonic-gate 		    (toa->MGMT_flags == T_SUCCESS) &&
132*0Sstevel@tonic-gate 		    (req->len == 0)) {
133*0Sstevel@tonic-gate 			if (debug)
134*0Sstevel@tonic-gate 				msgout("mibget getmsg() %d returned EOD "
135*0Sstevel@tonic-gate 				    "(level %lu, name %lu)",
136*0Sstevel@tonic-gate 				    j, req->level, req->name);
137*0Sstevel@tonic-gate 			return (first_item);		/* this is EOD msg */
138*0Sstevel@tonic-gate 		}
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 		if (ctlbuf.len >= sizeof (struct T_error_ack) &&
141*0Sstevel@tonic-gate 		    tea->PRIM_type == T_ERROR_ACK) {
142*0Sstevel@tonic-gate 			msgout("mibget %d gives T_ERROR_ACK: "
143*0Sstevel@tonic-gate 			    "TLI_error = 0x%lx, UNIX_error = 0x%lx",
144*0Sstevel@tonic-gate 			    j, tea->TLI_error, tea->UNIX_error);
145*0Sstevel@tonic-gate 			errno = (tea->TLI_error == TSYSERR)
146*0Sstevel@tonic-gate 				? tea->UNIX_error : EPROTO;
147*0Sstevel@tonic-gate 			goto error_exit;
148*0Sstevel@tonic-gate 		}
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 		if (getcode != MOREDATA ||
151*0Sstevel@tonic-gate 		    ctlbuf.len < sizeof (struct T_optmgmt_ack) ||
152*0Sstevel@tonic-gate 		    toa->PRIM_type != T_OPTMGMT_ACK ||
153*0Sstevel@tonic-gate 		    toa->MGMT_flags != T_SUCCESS) {
154*0Sstevel@tonic-gate 			msgout("mibget getmsg(ctl) %d returned %d, "
155*0Sstevel@tonic-gate 			    "ctlbuf.len = %d, PRIM_type = %ld",
156*0Sstevel@tonic-gate 			    j, getcode, ctlbuf.len, toa->PRIM_type);
157*0Sstevel@tonic-gate 			if (toa->PRIM_type == T_OPTMGMT_ACK)
158*0Sstevel@tonic-gate 				msgout("T_OPTMGMT_ACK: MGMT_flags = 0x%lx, "
159*0Sstevel@tonic-gate 				    "req->len = %lu",
160*0Sstevel@tonic-gate 				    toa->MGMT_flags, req->len);
161*0Sstevel@tonic-gate 			errno = ENOMSG;
162*0Sstevel@tonic-gate 			goto error_exit;
163*0Sstevel@tonic-gate 		}
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 		temp = (mib_item_t *)malloc(sizeof (mib_item_t));
166*0Sstevel@tonic-gate 		if (!temp) {
167*0Sstevel@tonic-gate 			perror("mibget malloc failed");
168*0Sstevel@tonic-gate 			goto error_exit;
169*0Sstevel@tonic-gate 		}
170*0Sstevel@tonic-gate 		if (last_item)
171*0Sstevel@tonic-gate 			last_item->next_item = temp;
172*0Sstevel@tonic-gate 		else
173*0Sstevel@tonic-gate 			first_item = temp;
174*0Sstevel@tonic-gate 		last_item = temp;
175*0Sstevel@tonic-gate 		last_item->next_item = nilp(mib_item_t);
176*0Sstevel@tonic-gate 		last_item->group = req->level;
177*0Sstevel@tonic-gate 		last_item->mib_id = req->name;
178*0Sstevel@tonic-gate 		last_item->length = req->len;
179*0Sstevel@tonic-gate 		last_item->valp = (char *)malloc(req->len);
180*0Sstevel@tonic-gate 		if (debug)
181*0Sstevel@tonic-gate 			msgout(
182*0Sstevel@tonic-gate 			"msg %d:  group = %4ld   mib_id = %5ld   length = %ld",
183*0Sstevel@tonic-gate 				j, last_item->group, last_item->mib_id,
184*0Sstevel@tonic-gate 				last_item->length);
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 		databuf.maxlen = last_item->length;
187*0Sstevel@tonic-gate 		databuf.buf    = last_item->valp;
188*0Sstevel@tonic-gate 		databuf.len    = 0;
189*0Sstevel@tonic-gate 		flags = 0;
190*0Sstevel@tonic-gate 		getcode = getmsg(sd, nilp(struct strbuf), &databuf, &flags);
191*0Sstevel@tonic-gate 		if (getcode == -1) {
192*0Sstevel@tonic-gate 			perror("mibget getmsg(data) failed");
193*0Sstevel@tonic-gate 			goto error_exit;
194*0Sstevel@tonic-gate 		} else if (getcode != 0) {
195*0Sstevel@tonic-gate 			msgout("xmibget getmsg(data) returned %d, "
196*0Sstevel@tonic-gate 			    "databuf.maxlen = %d, databuf.len = %d",
197*0Sstevel@tonic-gate 			    getcode, databuf.maxlen, databuf.len);
198*0Sstevel@tonic-gate 			goto error_exit;
199*0Sstevel@tonic-gate 		}
200*0Sstevel@tonic-gate 	}
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate error_exit:
203*0Sstevel@tonic-gate 	free_itemlist(first_item);
204*0Sstevel@tonic-gate 	return (NULL);
205*0Sstevel@tonic-gate }
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate static void
free_itemlist(mib_item_t * item_list)208*0Sstevel@tonic-gate free_itemlist(mib_item_t *item_list)
209*0Sstevel@tonic-gate {
210*0Sstevel@tonic-gate 	mib_item_t	*item;
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	while (item_list) {
213*0Sstevel@tonic-gate 		item = item_list;
214*0Sstevel@tonic-gate 		item_list = item->next_item;
215*0Sstevel@tonic-gate 		if (item->valp)
216*0Sstevel@tonic-gate 			free(item->valp);
217*0Sstevel@tonic-gate 		free(item);
218*0Sstevel@tonic-gate 	}
219*0Sstevel@tonic-gate }
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate /*
222*0Sstevel@tonic-gate  * If we are a router, return address of interface closest to client.
223*0Sstevel@tonic-gate  * If we are not a router, look through our routing table and return
224*0Sstevel@tonic-gate  * address of "best" router that is on same net as client.
225*0Sstevel@tonic-gate  *
226*0Sstevel@tonic-gate  * We expect the router flag to show up first, followed by interface
227*0Sstevel@tonic-gate  * addr group, followed by the routing table.
228*0Sstevel@tonic-gate  */
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate in_addr_t
get_ip_route(struct in_addr client_addr)231*0Sstevel@tonic-gate get_ip_route(struct in_addr client_addr)
232*0Sstevel@tonic-gate {
233*0Sstevel@tonic-gate 	boolean_t	found;
234*0Sstevel@tonic-gate 	mib_item_t	*item_list;
235*0Sstevel@tonic-gate 	mib_item_t	*item;
236*0Sstevel@tonic-gate 	int		sd;
237*0Sstevel@tonic-gate 	mib2_ip_t		*mip;
238*0Sstevel@tonic-gate 	mib2_ipAddrEntry_t	*map;
239*0Sstevel@tonic-gate 	mib2_ipRouteEntry_t	*rp;
240*0Sstevel@tonic-gate 	int			ip_forwarding = 2;	/* off */
241*0Sstevel@tonic-gate 	/* mask of interface used to route to client and best_router */
242*0Sstevel@tonic-gate 	struct in_addr		interface_mask;
243*0Sstevel@tonic-gate 	/* address of interface used to route to client and best_router */
244*0Sstevel@tonic-gate 	struct in_addr		interface_addr;
245*0Sstevel@tonic-gate 	/* address of "best router"; i.e. the answer */
246*0Sstevel@tonic-gate 	struct in_addr		best_router;
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate 	interface_mask.s_addr = 0L;
249*0Sstevel@tonic-gate 	interface_addr.s_addr = 0L;
250*0Sstevel@tonic-gate 	best_router.s_addr = 0L;
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	/* open a stream to IP */
253*0Sstevel@tonic-gate 	sd = open("/dev/ip", O_RDWR);
254*0Sstevel@tonic-gate 	if (sd == -1) {
255*0Sstevel@tonic-gate 		perror("ip open");
256*0Sstevel@tonic-gate 		(void) close(sd);
257*0Sstevel@tonic-gate 		msgout("can't open mib stream");
258*0Sstevel@tonic-gate 		return (0);
259*0Sstevel@tonic-gate 	}
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	/* send down a request and suck up all the mib info from IP */
262*0Sstevel@tonic-gate 	if ((item_list = mibget(sd)) == nilp(mib_item_t)) {
263*0Sstevel@tonic-gate 		msgout("mibget() failed");
264*0Sstevel@tonic-gate 		(void) close(sd);
265*0Sstevel@tonic-gate 		return (0);
266*0Sstevel@tonic-gate 	}
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	/*
269*0Sstevel@tonic-gate 	 * We make three passes through the list of collected IP mib
270*0Sstevel@tonic-gate 	 * information.  First we figure out if we are a router.  Next,
271*0Sstevel@tonic-gate 	 * we find which of our interfaces is on the same subnet as
272*0Sstevel@tonic-gate 	 * the client.  Third, we paw through our own routing table
273*0Sstevel@tonic-gate 	 * looking for a useful router address.
274*0Sstevel@tonic-gate 	 */
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	/*
277*0Sstevel@tonic-gate 	 * The general IP group.
278*0Sstevel@tonic-gate 	 */
279*0Sstevel@tonic-gate 	for (item = item_list; item; item = item->next_item) {
280*0Sstevel@tonic-gate 		if ((item->group == MIB2_IP) && (item->mib_id == 0)) {
281*0Sstevel@tonic-gate 			/* are we an IP router? */
282*0Sstevel@tonic-gate 			mip = (mib2_ip_t *)(void *)item->valp;
283*0Sstevel@tonic-gate 			ip_forwarding = mip->ipForwarding;
284*0Sstevel@tonic-gate 			break;
285*0Sstevel@tonic-gate 		}
286*0Sstevel@tonic-gate 	}
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	/*
289*0Sstevel@tonic-gate 	 * The interface group.
290*0Sstevel@tonic-gate 	 */
291*0Sstevel@tonic-gate 	for (item = item_list, found = B_FALSE; item != NULL && !found;
292*0Sstevel@tonic-gate 	    item = item->next_item) {
293*0Sstevel@tonic-gate 		if ((item->group == MIB2_IP) && (item->mib_id == MIB2_IP_20)) {
294*0Sstevel@tonic-gate 			/*
295*0Sstevel@tonic-gate 			 * Try to find out which interface is up, configured,
296*0Sstevel@tonic-gate 			 * not loopback, and on the same subnet as the client.
297*0Sstevel@tonic-gate 			 * Save its address and netmask.
298*0Sstevel@tonic-gate 			 */
299*0Sstevel@tonic-gate 			map = (mib2_ipAddrEntry_t *)(void *)item->valp;
300*0Sstevel@tonic-gate 			while ((char *)map < item->valp + item->length) {
301*0Sstevel@tonic-gate 				in_addr_t	addr, mask, net;
302*0Sstevel@tonic-gate 				int		ifflags;
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 				ifflags = map->ipAdEntInfo.ae_flags;
305*0Sstevel@tonic-gate 				addr = map->ipAdEntAddr;
306*0Sstevel@tonic-gate 				mask =  map->ipAdEntNetMask;
307*0Sstevel@tonic-gate 				net = addr & mask;
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 				if ((ifflags & IFF_LOOPBACK | IFF_UP) ==
310*0Sstevel@tonic-gate 				    IFF_UP && addr != INADDR_ANY &&
311*0Sstevel@tonic-gate 				    net == (client_addr.s_addr & mask)) {
312*0Sstevel@tonic-gate 					interface_addr.s_addr = addr;
313*0Sstevel@tonic-gate 					interface_mask.s_addr = mask;
314*0Sstevel@tonic-gate 					found = B_TRUE;
315*0Sstevel@tonic-gate 					break;
316*0Sstevel@tonic-gate 				}
317*0Sstevel@tonic-gate 				map++;
318*0Sstevel@tonic-gate 			}
319*0Sstevel@tonic-gate 		}
320*0Sstevel@tonic-gate 	}
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	/*
323*0Sstevel@tonic-gate 	 * If this exercise found no interface on the same subnet as
324*0Sstevel@tonic-gate 	 * the client, then we can't suggest any router address to
325*0Sstevel@tonic-gate 	 * use.
326*0Sstevel@tonic-gate 	 */
327*0Sstevel@tonic-gate 	if (interface_addr.s_addr == 0) {
328*0Sstevel@tonic-gate 		if (debug)
329*0Sstevel@tonic-gate 			msgout("get_ip_route: no interface on same net "
330*0Sstevel@tonic-gate 			    "as client");
331*0Sstevel@tonic-gate 		(void) close(sd);
332*0Sstevel@tonic-gate 		free_itemlist(item_list);
333*0Sstevel@tonic-gate 		return (0);
334*0Sstevel@tonic-gate 	}
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	/*
337*0Sstevel@tonic-gate 	 * If we are a router, we return to client the address of our
338*0Sstevel@tonic-gate 	 * interface on the same net as the client.
339*0Sstevel@tonic-gate 	 */
340*0Sstevel@tonic-gate 	if (ip_forwarding == 1) {
341*0Sstevel@tonic-gate 		if (debug)
342*0Sstevel@tonic-gate 			msgout("get_ip_route: returning local addr %s",
343*0Sstevel@tonic-gate 				inet_ntoa(interface_addr));
344*0Sstevel@tonic-gate 		(void) close(sd);
345*0Sstevel@tonic-gate 		free_itemlist(item_list);
346*0Sstevel@tonic-gate 		return (interface_addr.s_addr);
347*0Sstevel@tonic-gate 	}
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	if (debug) {
350*0Sstevel@tonic-gate 		msgout("interface_addr = %s.", inet_ntoa(interface_addr));
351*0Sstevel@tonic-gate 		msgout("interface_mask = %s", inet_ntoa(interface_mask));
352*0Sstevel@tonic-gate 	}
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	/*
356*0Sstevel@tonic-gate 	 * The routing table group.
357*0Sstevel@tonic-gate 	 */
358*0Sstevel@tonic-gate 	for (item = item_list; item; item = item->next_item) {
359*0Sstevel@tonic-gate 		if ((item->group == MIB2_IP) && (item->mib_id == MIB2_IP_21)) {
360*0Sstevel@tonic-gate 			if (debug)
361*0Sstevel@tonic-gate 				msgout("%lu records for ipRouteEntryTable",
362*0Sstevel@tonic-gate 					item->length /
363*0Sstevel@tonic-gate 					sizeof (mib2_ipRouteEntry_t));
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 			for (rp = (mib2_ipRouteEntry_t *)(void *)item->valp;
366*0Sstevel@tonic-gate 				(char *)rp < item->valp + item->length;
367*0Sstevel@tonic-gate 				rp++) {
368*0Sstevel@tonic-gate 				if (debug >= 2)
369*0Sstevel@tonic-gate 					msgout("ire_type = %d, next_hop = 0x%x",
370*0Sstevel@tonic-gate 						rp->ipRouteInfo.re_ire_type,
371*0Sstevel@tonic-gate 						rp->ipRouteNextHop);
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 				/*
374*0Sstevel@tonic-gate 				 * We are only interested in real
375*0Sstevel@tonic-gate 				 * gateway routes.
376*0Sstevel@tonic-gate 				 */
377*0Sstevel@tonic-gate 				if ((rp->ipRouteInfo.re_ire_type !=
378*0Sstevel@tonic-gate 				    IRE_DEFAULT) &&
379*0Sstevel@tonic-gate 				    (rp->ipRouteInfo.re_ire_type !=
380*0Sstevel@tonic-gate 				    IRE_PREFIX) &&
381*0Sstevel@tonic-gate 				    (rp->ipRouteInfo.re_ire_type !=
382*0Sstevel@tonic-gate 				    IRE_HOST) &&
383*0Sstevel@tonic-gate 				    (rp->ipRouteInfo.re_ire_type !=
384*0Sstevel@tonic-gate 				    IRE_HOST_REDIRECT))
385*0Sstevel@tonic-gate 					continue;
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 				/*
388*0Sstevel@tonic-gate 				 * We are only interested in routes with
389*0Sstevel@tonic-gate 				 * a next hop on the same subnet as
390*0Sstevel@tonic-gate 				 * the client.
391*0Sstevel@tonic-gate 				 */
392*0Sstevel@tonic-gate 				if ((rp->ipRouteNextHop &
393*0Sstevel@tonic-gate 					interface_mask.s_addr) !=
394*0Sstevel@tonic-gate 				    (interface_addr.s_addr &
395*0Sstevel@tonic-gate 					interface_mask.s_addr))
396*0Sstevel@tonic-gate 					continue;
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 				/*
399*0Sstevel@tonic-gate 				 * We have a valid route.  Give preference
400*0Sstevel@tonic-gate 				 * to default routes.
401*0Sstevel@tonic-gate 				 */
402*0Sstevel@tonic-gate 				if ((rp->ipRouteDest == 0) ||
403*0Sstevel@tonic-gate 				    (best_router.s_addr == 0))
404*0Sstevel@tonic-gate 					best_router.s_addr =
405*0Sstevel@tonic-gate 						rp->ipRouteNextHop;
406*0Sstevel@tonic-gate 			}
407*0Sstevel@tonic-gate 		}
408*0Sstevel@tonic-gate 	}
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	if (debug && (best_router.s_addr == 0))
411*0Sstevel@tonic-gate 		msgout("get_ip_route: no route found for client");
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 	(void) close(sd);
414*0Sstevel@tonic-gate 	free_itemlist(item_list);
415*0Sstevel@tonic-gate 	return (best_router.s_addr);
416*0Sstevel@tonic-gate }
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate /*
419*0Sstevel@tonic-gate  * Return address of server interface closest to client.
420*0Sstevel@tonic-gate  *
421*0Sstevel@tonic-gate  * If the server has only a single IP address return it. Otherwise check
422*0Sstevel@tonic-gate  * if the server has an interface on the same subnet as the client and
423*0Sstevel@tonic-gate  * return the address of that interface.
424*0Sstevel@tonic-gate  */
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate in_addr_t
find_best_server_int(char ** addr_list,char * client_name)427*0Sstevel@tonic-gate find_best_server_int(char **addr_list, char *client_name)
428*0Sstevel@tonic-gate {
429*0Sstevel@tonic-gate 	in_addr_t		server_addr = 0;
430*0Sstevel@tonic-gate 	struct hostent		h, *hp;
431*0Sstevel@tonic-gate 	char			hbuf[NSS_BUFLEN_HOSTS];
432*0Sstevel@tonic-gate 	int			err;
433*0Sstevel@tonic-gate 	struct in_addr		client_addr;
434*0Sstevel@tonic-gate 	mib_item_t		*item_list;
435*0Sstevel@tonic-gate 	mib_item_t		*item;
436*0Sstevel@tonic-gate 	int			sd;
437*0Sstevel@tonic-gate 	mib2_ipAddrEntry_t	*map;
438*0Sstevel@tonic-gate 	in_addr_t		client_net = 0, client_mask = 0;
439*0Sstevel@tonic-gate 	boolean_t		found_client_int;
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	(void) memcpy(&server_addr, addr_list[0], sizeof (in_addr_t));
442*0Sstevel@tonic-gate 	if (addr_list[1] == NULL)
443*0Sstevel@tonic-gate 		return (server_addr);
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	hp = gethostbyname_r(client_name, &h, hbuf, sizeof (hbuf), &err);
446*0Sstevel@tonic-gate 	if (hp == NULL)
447*0Sstevel@tonic-gate 		return (server_addr);
448*0Sstevel@tonic-gate 	(void) memcpy(&client_addr, hp->h_addr_list[0], sizeof (client_addr));
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	/* open a stream to IP */
451*0Sstevel@tonic-gate 	sd = open("/dev/ip", O_RDWR);
452*0Sstevel@tonic-gate 	if (sd == -1) {
453*0Sstevel@tonic-gate 		perror("ip open");
454*0Sstevel@tonic-gate 		(void) close(sd);
455*0Sstevel@tonic-gate 		msgout("can't open mib stream");
456*0Sstevel@tonic-gate 		return (server_addr);
457*0Sstevel@tonic-gate 	}
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 	/* send down a request and suck up all the mib info from IP */
460*0Sstevel@tonic-gate 	if ((item_list = mibget(sd)) == nilp(mib_item_t)) {
461*0Sstevel@tonic-gate 		msgout("mibget() failed");
462*0Sstevel@tonic-gate 		(void) close(sd);
463*0Sstevel@tonic-gate 		return (server_addr);
464*0Sstevel@tonic-gate 	}
465*0Sstevel@tonic-gate 	(void) close(sd);
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	/*
468*0Sstevel@tonic-gate 	 * Search through the list for our interface which is on the same
469*0Sstevel@tonic-gate 	 * subnet as the client and get the netmask.
470*0Sstevel@tonic-gate 	 */
471*0Sstevel@tonic-gate 	for (item = item_list, found_client_int = B_FALSE;
472*0Sstevel@tonic-gate 	    item != NULL && !found_client_int; item = item->next_item) {
473*0Sstevel@tonic-gate 		if ((item->group == MIB2_IP) && (item->mib_id == MIB2_IP_20)) {
474*0Sstevel@tonic-gate 			/*
475*0Sstevel@tonic-gate 			 * Try to find out which interface is up, configured,
476*0Sstevel@tonic-gate 			 * not loopback, and on the same subnet as the client.
477*0Sstevel@tonic-gate 			 * Save its address and netmask.
478*0Sstevel@tonic-gate 			 */
479*0Sstevel@tonic-gate 			map = (mib2_ipAddrEntry_t *)(void *)item->valp;
480*0Sstevel@tonic-gate 			while ((char *)map < item->valp + item->length) {
481*0Sstevel@tonic-gate 				in_addr_t	addr, mask, net;
482*0Sstevel@tonic-gate 				int		ifflags;
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 				ifflags = map->ipAdEntInfo.ae_flags;
485*0Sstevel@tonic-gate 				addr = map->ipAdEntAddr;
486*0Sstevel@tonic-gate 				mask =  map->ipAdEntNetMask;
487*0Sstevel@tonic-gate 				net = addr & mask;
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 				if ((ifflags & IFF_LOOPBACK|IFF_UP) == IFF_UP &&
490*0Sstevel@tonic-gate 				    addr != INADDR_ANY &&
491*0Sstevel@tonic-gate 				    (client_addr.s_addr & mask) == net) {
492*0Sstevel@tonic-gate 					client_net = net;
493*0Sstevel@tonic-gate 					client_mask = mask;
494*0Sstevel@tonic-gate 					found_client_int = B_TRUE;
495*0Sstevel@tonic-gate 					break;
496*0Sstevel@tonic-gate 				}
497*0Sstevel@tonic-gate 				map++;
498*0Sstevel@tonic-gate 			}
499*0Sstevel@tonic-gate 		}
500*0Sstevel@tonic-gate 	}
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	/*
503*0Sstevel@tonic-gate 	 * If we found the interface check which is the best IP address.
504*0Sstevel@tonic-gate 	 */
505*0Sstevel@tonic-gate 	if (found_client_int) {
506*0Sstevel@tonic-gate 		while (*addr_list != NULL) {
507*0Sstevel@tonic-gate 			in_addr_t	addr;
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 			(void) memcpy(&addr, *addr_list, sizeof (in_addr_t));
510*0Sstevel@tonic-gate 			if ((addr & client_mask) == client_net) {
511*0Sstevel@tonic-gate 				server_addr = addr;
512*0Sstevel@tonic-gate 				break;
513*0Sstevel@tonic-gate 			}
514*0Sstevel@tonic-gate 			addr_list++;
515*0Sstevel@tonic-gate 		}
516*0Sstevel@tonic-gate 	}
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	if (debug && server_addr == 0)
519*0Sstevel@tonic-gate 		msgout("No usable interface for returning reply");
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 	free_itemlist(item_list);
522*0Sstevel@tonic-gate 	return (server_addr);
523*0Sstevel@tonic-gate }
524