3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the Computer Systems
16 * Engineering Group at Lawrence Berkeley Laboratory.
17 * 4. Neither the name of the University nor of the Laboratory may be used
18 * to endorse or promote products derived from this software without
19 * specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 /* Seriously complex Solaris mib2 code */
37 static const char rcsid[] =
38 "@(#) $Id: findsaddr-mib.c,v 1.2 2000/12/13 21:31:49 leres Exp $ (LBL)";
41 #include <sys/param.h>
43 #include <sys/ioctl.h>
44 #include <sys/socket.h>
45 #ifdef HAVE_SYS_SOCKIO_H
46 #include <sys/sockio.h>
48 #include <sys/time.h> /* concession to AIX */
49 #include <sys/stream.h>
50 #include <sys/tihdr.h>
51 #include <sys/tiuser.h>
59 #include <net/route.h>
61 #include <netinet/in.h>
63 #include <inet/common.h>
64 #include <inet/mib2.h>
68 #include <arpa/inet.h>
82 #ifdef HAVE_OS_PROTO_H
86 #include "findsaddr.h"
88 /* Compatibility with older versions of Solaris */
90 #define IRE_CACHE IRE_ROUTE
94 #define T_CURRENT MI_T_CURRENT
98 struct routelist *next;
106 static struct routelist *getroutelist(char *);
107 static void freeroutelist(struct routelist *);
110 * Return the source address for the given destination address
112 * Since solaris doesn't report the interface associated with every
113 * route, we have to make two passes over the routing table. The
114 * first pass should yield a host, net, default or interface route.
115 * If we find an interface route we're done. If not, we need to
116 * make a second pass to find the interface route for the gateway
117 * in the host, net, default route we found in the first pass.
119 * So instead of making a single pass through the tables as they
120 * are retrieved from the kernel, we must build a linked list...
123 findsaddr(register const struct sockaddr_in *to,
124 register struct sockaddr_in *from)
126 register struct routelist *rl, *rl2, *routelist;
127 static char errbuf[512];
128 u_int32_t mask, gate;
130 /* Get the routing table */
131 routelist = getroutelist(errbuf);
132 if (routelist == NULL)
135 /* First pass; look for a route that matches */
138 for (rl = routelist; rl != NULL; rl = rl->next) {
139 if ((to->sin_addr.s_addr & rl->mask) == rl->dest &&
140 (rl->mask > mask || mask == 0) &&
147 freeroutelist(routelist);
148 sprintf(errbuf, "%s: %.128s",
149 inet_ntoa(to->sin_addr), strerror(EHOSTUNREACH));
153 /* We're done if we got one with an interface */
154 if (rl2->ifname[0] != '\0') {
155 freeroutelist(routelist);
156 from->sin_addr.s_addr = rl2->gate;
160 /* First pass; look for a route that matches the gateway we found */
164 for (rl = routelist; rl != NULL; rl = rl->next) {
165 if ((gate & rl->mask) == rl->dest &&
166 (rl->mask > mask || mask == 0) &&
168 rl->ifname[0] != '\0') {
174 freeroutelist(routelist);
175 sprintf(errbuf, "%s: %.128s (second pass)",
176 inet_ntoa(to->sin_addr), strerror(EHOSTUNREACH));
180 from->sin_addr.s_addr = rl2->gate;
181 freeroutelist(routelist);
187 struct T_optmgmt_req req;
193 struct T_optmgmt_ack ack;
198 static struct mibrq mibrq = {
199 { T_OPTMGMT_REQ, sizeof(mibrq.hdr), sizeof(mibrq.req), T_CURRENT },
203 static struct mibrep mibrep = {
209 static struct strbuf rqbuf = {
210 0, sizeof(mibrq), (char *)&mibrq
213 static struct strbuf repbuf = {
214 sizeof(mibrep.buf), sizeof(mibrep.ack) + sizeof(mibrep.hdr),
218 static const char devip[] = "/dev/ip";
221 * Construct the list of routes
223 static struct routelist *
224 getroutelist(char *errbuf)
226 register int s, stat, i;
228 register struct T_optmgmt_ack *ackp;
229 register struct T_error_ack *eackp;
230 register struct opthdr *hp;
231 register mib2_ipRouteEntry_t *rp, *rp2;
232 register struct routelist *rl, *rl2, *routelist;
234 struct strbuf repbuf2;
236 s = open(devip, O_RDWR, 0);
238 sprintf(errbuf, "open %s: %.128s", devip, strerror(errno));
242 if ((cp = "arp", ioctl(s, I_PUSH, cp) < 0) ||
243 (cp = "tcp", ioctl(s, I_PUSH, cp) < 0) ||
244 (cp = "udp", ioctl(s, I_PUSH, cp) < 0)) {
245 sprintf(errbuf, "I_PUSH %s: %.128s", cp, strerror(errno));
251 if (putmsg(s, &rqbuf, NULL, flags) < 0) {
252 sprintf(errbuf, "putmsg: %.128s", strerror(errno));
264 eackp = (struct T_error_ack *)ackp;
267 memset(repbuf.buf, 0, repbuf.len);
268 stat = getmsg(s, &repbuf, NULL, &flags);
270 sprintf(errbuf, "getmsg: %.128s", strerror(errno));
273 if (stat == 0 && repbuf.len >= sizeof(*ackp) &&
274 ackp->PRIM_type == T_OPTMGMT_ACK &&
275 ackp->MGMT_flags == T_SUCCESS &&
280 if (repbuf.len >= sizeof(*eackp) &&
281 eackp->PRIM_type == T_ERROR_ACK) {
282 sprintf(errbuf, "getmsg err: %.128s",
283 strerror((eackp->TLI_error == TSYSERR) ?
284 eackp->UNIX_error : EPROTO));
287 if (stat != MOREDATA ||
288 repbuf.len < sizeof(*ackp) ||
289 ackp->PRIM_type != T_OPTMGMT_ACK ||
290 ackp->MGMT_flags != T_SUCCESS) {
291 strcpy(errbuf, "unknown getmsg err");
295 memset(&repbuf2, 0, sizeof(repbuf2));
296 repbuf2.maxlen = hp->len;
297 rp = malloc(hp->len);
299 sprintf(errbuf, "malloc: %.128s", strerror(errno));
302 repbuf2.buf = (char *)rp;
305 memset(repbuf2.buf, 0, repbuf2.len);
306 stat = getmsg(s, NULL, &repbuf2, &flags);
308 sprintf(errbuf, "getmsg2: %.128s", strerror(errno));
312 /* Spin through the routes */
314 for (rp2 = rp; (char *)rp2 < (char *)rp + repbuf2.len; ++rp2) {
315 if (hp->level != MIB2_IP || hp->name != MIB2_IP_21)
318 if (rp2->ipRouteInfo.re_ire_type == IRE_CACHE ||
319 rp2->ipRouteInfo.re_ire_type == IRE_BROADCAST)
322 /* Got one we want to keep */
323 rl = malloc(sizeof(*rl));
326 "malloc 2: %.128s", strerror(errno));
329 memset(rl, 0, sizeof(*rl));
331 rl->mask = rp2->ipRouteMask;
332 rl->dest = rp2->ipRouteDest;
333 rl->gate = rp2->ipRouteNextHop;
334 if (rp2->ipRouteIfIndex.o_length > 0) {
335 i = rp2->ipRouteIfIndex.o_length;
336 if (i > sizeof(rl->ifname) - 1)
337 i = sizeof(rl->ifname) - 1;
339 rp2->ipRouteIfIndex.o_bytes, i);
340 rl->ifname[i] = '\0';
343 /* Keep in order (just for fun) */
344 if (routelist == NULL)
354 strcpy(errbuf, "failed!");
357 if (routelist != NULL) {
358 freeroutelist(routelist);
369 freeroutelist(register struct routelist *rl)
371 register struct routelist *rl2;