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