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