1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate 6*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 7*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 8*7c478bd9Sstevel@tonic-gate 9*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */ 10*7c478bd9Sstevel@tonic-gate 11*7c478bd9Sstevel@tonic-gate /* 12*7c478bd9Sstevel@tonic-gate * 13*7c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1989, 1991, 1993 14*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 15*7c478bd9Sstevel@tonic-gate * 16*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 17*7c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 18*7c478bd9Sstevel@tonic-gate * are met: 19*7c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 20*7c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 21*7c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 22*7c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 23*7c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 24*7c478bd9Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 25*7c478bd9Sstevel@tonic-gate * must display the following acknowledgement: 26*7c478bd9Sstevel@tonic-gate * This product includes software developed by the University of 27*7c478bd9Sstevel@tonic-gate * California, Berkeley and its contributors. 28*7c478bd9Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors 29*7c478bd9Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 30*7c478bd9Sstevel@tonic-gate * without specific prior written permission. 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33*7c478bd9Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34*7c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35*7c478bd9Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36*7c478bd9Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37*7c478bd9Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38*7c478bd9Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39*7c478bd9Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40*7c478bd9Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41*7c478bd9Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42*7c478bd9Sstevel@tonic-gate * SUCH DAMAGE. 43*7c478bd9Sstevel@tonic-gate * 44*7c478bd9Sstevel@tonic-gate * @(#)route.c 8.6 (Berkeley) 4/28/95 45*7c478bd9Sstevel@tonic-gate * @(#)linkaddr.c 8.1 (Berkeley) 6/4/93 46*7c478bd9Sstevel@tonic-gate */ 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate #include <net/if.h> 59*7c478bd9Sstevel@tonic-gate #include <net/route.h> 60*7c478bd9Sstevel@tonic-gate #include <net/if_dl.h> 61*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 62*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 63*7c478bd9Sstevel@tonic-gate #include <netdb.h> 64*7c478bd9Sstevel@tonic-gate #include <inet/mib2.h> 65*7c478bd9Sstevel@tonic-gate #include <inet/ip.h> 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate #include <locale.h> 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate #include <errno.h> 70*7c478bd9Sstevel@tonic-gate #include <unistd.h> 71*7c478bd9Sstevel@tonic-gate #include <stdio.h> 72*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 73*7c478bd9Sstevel@tonic-gate #include <string.h> 74*7c478bd9Sstevel@tonic-gate #include <stropts.h> 75*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 76*7c478bd9Sstevel@tonic-gate #include <assert.h> 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate static struct keytab { 79*7c478bd9Sstevel@tonic-gate char *kt_cp; 80*7c478bd9Sstevel@tonic-gate int kt_i; 81*7c478bd9Sstevel@tonic-gate } keywords[] = { 82*7c478bd9Sstevel@tonic-gate #define K_ADD 1 83*7c478bd9Sstevel@tonic-gate {"add", K_ADD}, 84*7c478bd9Sstevel@tonic-gate #define K_BLACKHOLE 2 85*7c478bd9Sstevel@tonic-gate {"blackhole", K_BLACKHOLE}, 86*7c478bd9Sstevel@tonic-gate #define K_CHANGE 3 87*7c478bd9Sstevel@tonic-gate {"change", K_CHANGE}, 88*7c478bd9Sstevel@tonic-gate #define K_CLONING 4 89*7c478bd9Sstevel@tonic-gate {"cloning", K_CLONING}, 90*7c478bd9Sstevel@tonic-gate #define K_DELETE 5 91*7c478bd9Sstevel@tonic-gate {"delete", K_DELETE}, 92*7c478bd9Sstevel@tonic-gate #define K_DST 6 93*7c478bd9Sstevel@tonic-gate {"dst", K_DST}, 94*7c478bd9Sstevel@tonic-gate #define K_EXPIRE 7 95*7c478bd9Sstevel@tonic-gate {"expire", K_EXPIRE}, 96*7c478bd9Sstevel@tonic-gate #define K_FLUSH 8 97*7c478bd9Sstevel@tonic-gate {"flush", K_FLUSH}, 98*7c478bd9Sstevel@tonic-gate #define K_GATEWAY 9 99*7c478bd9Sstevel@tonic-gate {"gateway", K_GATEWAY}, 100*7c478bd9Sstevel@tonic-gate #define K_GET 11 101*7c478bd9Sstevel@tonic-gate {"get", K_GET}, 102*7c478bd9Sstevel@tonic-gate #define K_HOPCOUNT 12 103*7c478bd9Sstevel@tonic-gate {"hopcount", K_HOPCOUNT}, 104*7c478bd9Sstevel@tonic-gate #define K_HOST 13 105*7c478bd9Sstevel@tonic-gate {"host", K_HOST}, 106*7c478bd9Sstevel@tonic-gate #define K_IFA 14 107*7c478bd9Sstevel@tonic-gate {"ifa", K_IFA}, 108*7c478bd9Sstevel@tonic-gate #define K_IFACE 15 109*7c478bd9Sstevel@tonic-gate {"iface", K_IFACE}, 110*7c478bd9Sstevel@tonic-gate #define K_IFP 16 111*7c478bd9Sstevel@tonic-gate {"ifp", K_IFP}, 112*7c478bd9Sstevel@tonic-gate #define K_INET 17 113*7c478bd9Sstevel@tonic-gate {"inet", K_INET}, 114*7c478bd9Sstevel@tonic-gate #define K_INET6 18 115*7c478bd9Sstevel@tonic-gate {"inet6", K_INET6}, 116*7c478bd9Sstevel@tonic-gate #define K_INTERFACE 19 117*7c478bd9Sstevel@tonic-gate {"interface", K_INTERFACE}, 118*7c478bd9Sstevel@tonic-gate #define K_LINK 20 119*7c478bd9Sstevel@tonic-gate {"link", K_LINK}, 120*7c478bd9Sstevel@tonic-gate #define K_LOCK 21 121*7c478bd9Sstevel@tonic-gate {"lock", K_LOCK}, 122*7c478bd9Sstevel@tonic-gate #define K_LOCKREST 22 123*7c478bd9Sstevel@tonic-gate {"lockrest", K_LOCKREST}, 124*7c478bd9Sstevel@tonic-gate #define K_MASK 23 125*7c478bd9Sstevel@tonic-gate {"mask", K_MASK}, 126*7c478bd9Sstevel@tonic-gate #define K_MONITOR 24 127*7c478bd9Sstevel@tonic-gate {"monitor", K_MONITOR}, 128*7c478bd9Sstevel@tonic-gate #define K_MTU 25 129*7c478bd9Sstevel@tonic-gate {"mtu", K_MTU}, 130*7c478bd9Sstevel@tonic-gate #define K_NET 26 131*7c478bd9Sstevel@tonic-gate {"net", K_NET}, 132*7c478bd9Sstevel@tonic-gate #define K_NETMASK 27 133*7c478bd9Sstevel@tonic-gate {"netmask", K_NETMASK}, 134*7c478bd9Sstevel@tonic-gate #define K_NOSTATIC 28 135*7c478bd9Sstevel@tonic-gate {"nostatic", K_NOSTATIC}, 136*7c478bd9Sstevel@tonic-gate #define K_PRIVATE 29 137*7c478bd9Sstevel@tonic-gate {"private", K_PRIVATE}, 138*7c478bd9Sstevel@tonic-gate #define K_PROTO1 30 139*7c478bd9Sstevel@tonic-gate {"proto1", K_PROTO1}, 140*7c478bd9Sstevel@tonic-gate #define K_PROTO2 31 141*7c478bd9Sstevel@tonic-gate {"proto2", K_PROTO2}, 142*7c478bd9Sstevel@tonic-gate #define K_RECVPIPE 32 143*7c478bd9Sstevel@tonic-gate {"recvpipe", K_RECVPIPE}, 144*7c478bd9Sstevel@tonic-gate #define K_REJECT 33 145*7c478bd9Sstevel@tonic-gate {"reject", K_REJECT}, 146*7c478bd9Sstevel@tonic-gate #define K_RTT 34 147*7c478bd9Sstevel@tonic-gate {"rtt", K_RTT}, 148*7c478bd9Sstevel@tonic-gate #define K_RTTVAR 35 149*7c478bd9Sstevel@tonic-gate {"rttvar", K_RTTVAR}, 150*7c478bd9Sstevel@tonic-gate #define K_SA 36 151*7c478bd9Sstevel@tonic-gate {"sa", K_SA}, 152*7c478bd9Sstevel@tonic-gate #define K_SENDPIPE 37 153*7c478bd9Sstevel@tonic-gate {"sendpipe", K_SENDPIPE}, 154*7c478bd9Sstevel@tonic-gate #define K_SSTHRESH 38 155*7c478bd9Sstevel@tonic-gate {"ssthresh", K_SSTHRESH}, 156*7c478bd9Sstevel@tonic-gate #define K_STATIC 39 157*7c478bd9Sstevel@tonic-gate {"static", K_STATIC}, 158*7c478bd9Sstevel@tonic-gate #define K_XRESOLVE 40 159*7c478bd9Sstevel@tonic-gate {"xresolve", K_XRESOLVE}, 160*7c478bd9Sstevel@tonic-gate #define K_MULTIRT 41 161*7c478bd9Sstevel@tonic-gate {"multirt", K_MULTIRT}, 162*7c478bd9Sstevel@tonic-gate #define K_SETSRC 42 163*7c478bd9Sstevel@tonic-gate {"setsrc", K_SETSRC}, 164*7c478bd9Sstevel@tonic-gate {0, 0} 165*7c478bd9Sstevel@tonic-gate }; 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate static union sockunion { 168*7c478bd9Sstevel@tonic-gate struct sockaddr sa; 169*7c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 170*7c478bd9Sstevel@tonic-gate struct sockaddr_dl sdl; 171*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 172*7c478bd9Sstevel@tonic-gate } so_dst, so_gate, so_mask, so_ifa, so_ifp, so_src; 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate typedef struct mib_item_s { 175*7c478bd9Sstevel@tonic-gate struct mib_item_s *next_item; 176*7c478bd9Sstevel@tonic-gate long group; 177*7c478bd9Sstevel@tonic-gate long mib_id; 178*7c478bd9Sstevel@tonic-gate long length; 179*7c478bd9Sstevel@tonic-gate intmax_t *valp; 180*7c478bd9Sstevel@tonic-gate } mib_item_t; 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate typedef union sockunion *sup; 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate static void bprintf(FILE *fp, int b, char *s); 185*7c478bd9Sstevel@tonic-gate static void delRouteEntry(mib2_ipRouteEntry_t *rp, 186*7c478bd9Sstevel@tonic-gate mib2_ipv6RouteEntry_t *rp6, int seqno); 187*7c478bd9Sstevel@tonic-gate static void flushroutes(int argc, char *argv[]); 188*7c478bd9Sstevel@tonic-gate static boolean_t getaddr(int which, char *s, struct hostent **hpp); 189*7c478bd9Sstevel@tonic-gate static boolean_t in6_getaddr(char *s, struct sockaddr_in6 *sin6, 190*7c478bd9Sstevel@tonic-gate int *plenp, struct hostent **hpp); 191*7c478bd9Sstevel@tonic-gate static boolean_t in_getaddr(char *s, struct sockaddr_in *sin, 192*7c478bd9Sstevel@tonic-gate int *plenp, int which, struct hostent **hpp); 193*7c478bd9Sstevel@tonic-gate static int in_getprefixlen(char *addr, int max_plen); 194*7c478bd9Sstevel@tonic-gate static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 195*7c478bd9Sstevel@tonic-gate uchar_t *mask); 196*7c478bd9Sstevel@tonic-gate static void inet_makenetandmask(in_addr_t net, 197*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin); 198*7c478bd9Sstevel@tonic-gate static in_addr_t inet_makesubnetmask(in_addr_t addr, in_addr_t mask); 199*7c478bd9Sstevel@tonic-gate static int keyword(char *cp); 200*7c478bd9Sstevel@tonic-gate static void link_addr(const char *addr, struct sockaddr_dl *sdl); 201*7c478bd9Sstevel@tonic-gate static char *link_ntoa(const struct sockaddr_dl *sdl); 202*7c478bd9Sstevel@tonic-gate static mib_item_t *mibget(int sd); 203*7c478bd9Sstevel@tonic-gate static char *netname(struct sockaddr *sa); 204*7c478bd9Sstevel@tonic-gate static int newroute(int argc, char **argv); 205*7c478bd9Sstevel@tonic-gate static void pmsg_addrs(char *cp, int addrs); 206*7c478bd9Sstevel@tonic-gate static void pmsg_common(struct rt_msghdr *rtm); 207*7c478bd9Sstevel@tonic-gate static void print_getmsg(struct rt_msghdr *rtm, int msglen); 208*7c478bd9Sstevel@tonic-gate static void print_rtmsg(struct rt_msghdr *rtm, int msglen); 209*7c478bd9Sstevel@tonic-gate static void quit(char *s, int err); 210*7c478bd9Sstevel@tonic-gate static char *routename(struct sockaddr *sa); 211*7c478bd9Sstevel@tonic-gate static void rtmonitor(int argc, char *argv[]); 212*7c478bd9Sstevel@tonic-gate static int rtmsg(int cmd, int flags); 213*7c478bd9Sstevel@tonic-gate static int salen(struct sockaddr *sa); 214*7c478bd9Sstevel@tonic-gate static void set_metric(char *value, int key); 215*7c478bd9Sstevel@tonic-gate static void sockaddr(char *addr, struct sockaddr *sa); 216*7c478bd9Sstevel@tonic-gate static void sodump(sup su, char *which); 217*7c478bd9Sstevel@tonic-gate static void usage(char *cp); 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate static int pid, rtm_addrs; 220*7c478bd9Sstevel@tonic-gate static int s; 221*7c478bd9Sstevel@tonic-gate static boolean_t forcehost, forcenet, nflag; 222*7c478bd9Sstevel@tonic-gate static int af = AF_INET; 223*7c478bd9Sstevel@tonic-gate static boolean_t qflag, tflag; 224*7c478bd9Sstevel@tonic-gate static boolean_t iflag, verbose; 225*7c478bd9Sstevel@tonic-gate static boolean_t locking, lockrest, debugonly; 226*7c478bd9Sstevel@tonic-gate static boolean_t fflag; 227*7c478bd9Sstevel@tonic-gate static struct rt_metrics rt_metrics; 228*7c478bd9Sstevel@tonic-gate static ulong_t rtm_inits; 229*7c478bd9Sstevel@tonic-gate static int masklen; 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate static struct { 232*7c478bd9Sstevel@tonic-gate struct rt_msghdr m_rtm; 233*7c478bd9Sstevel@tonic-gate char m_space[512]; 234*7c478bd9Sstevel@tonic-gate } m_rtmsg; 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate /* 237*7c478bd9Sstevel@tonic-gate * Sizes of data structures extracted from the base mib. 238*7c478bd9Sstevel@tonic-gate * This allows the size of the tables entries to grow while preserving 239*7c478bd9Sstevel@tonic-gate * binary compatibility. 240*7c478bd9Sstevel@tonic-gate */ 241*7c478bd9Sstevel@tonic-gate static int ipRouteEntrySize; 242*7c478bd9Sstevel@tonic-gate static int ipv6RouteEntrySize; 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate #define ROUNDUP_LONG(a) \ 245*7c478bd9Sstevel@tonic-gate ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long)) 246*7c478bd9Sstevel@tonic-gate #define ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n))) 247*7c478bd9Sstevel@tonic-gate #define C(x) ((x) & 0xff) 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate /* 250*7c478bd9Sstevel@tonic-gate * return values from in_getprefixlen() 251*7c478bd9Sstevel@tonic-gate */ 252*7c478bd9Sstevel@tonic-gate #define BAD_ADDR -1 /* prefix is invalid */ 253*7c478bd9Sstevel@tonic-gate #define NO_PREFIX -2 /* no prefix was found */ 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate void 256*7c478bd9Sstevel@tonic-gate usage(char *cp) 257*7c478bd9Sstevel@tonic-gate { 258*7c478bd9Sstevel@tonic-gate if (cp != NULL) 259*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: botched keyword: %s\n"), 260*7c478bd9Sstevel@tonic-gate cp); 261*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 262*7c478bd9Sstevel@tonic-gate gettext("usage: route [ -fnqv ] cmd [[ -<qualifers> ] args ]\n")); 263*7c478bd9Sstevel@tonic-gate exit(1); 264*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 265*7c478bd9Sstevel@tonic-gate } 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate void 268*7c478bd9Sstevel@tonic-gate quit(char *s, int sverrno) 269*7c478bd9Sstevel@tonic-gate { 270*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "route: "); 271*7c478bd9Sstevel@tonic-gate if (s != NULL) 272*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", s); 273*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", strerror(sverrno)); 274*7c478bd9Sstevel@tonic-gate exit(sverrno); 275*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 276*7c478bd9Sstevel@tonic-gate } 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate int 279*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 280*7c478bd9Sstevel@tonic-gate { 281*7c478bd9Sstevel@tonic-gate extern int optind; 282*7c478bd9Sstevel@tonic-gate int ch; 283*7c478bd9Sstevel@tonic-gate int key; 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 288*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 289*7c478bd9Sstevel@tonic-gate #endif 290*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate if (argc < 2) 293*7c478bd9Sstevel@tonic-gate usage((char *)NULL); 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate while ((ch = getopt(argc, argv, "nqdtvf")) != EOF) { 296*7c478bd9Sstevel@tonic-gate switch (ch) { 297*7c478bd9Sstevel@tonic-gate case 'n': 298*7c478bd9Sstevel@tonic-gate nflag = B_TRUE; 299*7c478bd9Sstevel@tonic-gate break; 300*7c478bd9Sstevel@tonic-gate case 'q': 301*7c478bd9Sstevel@tonic-gate qflag = B_TRUE; 302*7c478bd9Sstevel@tonic-gate break; 303*7c478bd9Sstevel@tonic-gate case 'v': 304*7c478bd9Sstevel@tonic-gate verbose = B_TRUE; 305*7c478bd9Sstevel@tonic-gate break; 306*7c478bd9Sstevel@tonic-gate case 't': 307*7c478bd9Sstevel@tonic-gate tflag = B_TRUE; 308*7c478bd9Sstevel@tonic-gate break; 309*7c478bd9Sstevel@tonic-gate case 'd': 310*7c478bd9Sstevel@tonic-gate debugonly = B_TRUE; 311*7c478bd9Sstevel@tonic-gate break; 312*7c478bd9Sstevel@tonic-gate case 'f': 313*7c478bd9Sstevel@tonic-gate fflag = B_TRUE; 314*7c478bd9Sstevel@tonic-gate break; 315*7c478bd9Sstevel@tonic-gate case '?': 316*7c478bd9Sstevel@tonic-gate default: 317*7c478bd9Sstevel@tonic-gate usage((char *)NULL); 318*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate } 321*7c478bd9Sstevel@tonic-gate argc -= optind; 322*7c478bd9Sstevel@tonic-gate argv += optind; 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate pid = getpid(); 325*7c478bd9Sstevel@tonic-gate if (tflag) 326*7c478bd9Sstevel@tonic-gate s = open("/dev/null", O_WRONLY); 327*7c478bd9Sstevel@tonic-gate else 328*7c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, 0); 329*7c478bd9Sstevel@tonic-gate if (s < 0) 330*7c478bd9Sstevel@tonic-gate quit("socket", errno); 331*7c478bd9Sstevel@tonic-gate if (fflag) { 332*7c478bd9Sstevel@tonic-gate /* 333*7c478bd9Sstevel@tonic-gate * Accept an address family keyword after the -f. Since the 334*7c478bd9Sstevel@tonic-gate * default address family is AF_INET, reassign af only for the 335*7c478bd9Sstevel@tonic-gate * other valid address families. 336*7c478bd9Sstevel@tonic-gate */ 337*7c478bd9Sstevel@tonic-gate if (*argv != NULL) { 338*7c478bd9Sstevel@tonic-gate switch (key = keyword(*argv)) { 339*7c478bd9Sstevel@tonic-gate case K_INET: 340*7c478bd9Sstevel@tonic-gate case K_INET6: 341*7c478bd9Sstevel@tonic-gate if (key == K_INET6) 342*7c478bd9Sstevel@tonic-gate af = AF_INET6; 343*7c478bd9Sstevel@tonic-gate /* Skip over the address family parameter. */ 344*7c478bd9Sstevel@tonic-gate argc--; 345*7c478bd9Sstevel@tonic-gate argv++; 346*7c478bd9Sstevel@tonic-gate break; 347*7c478bd9Sstevel@tonic-gate } 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate flushroutes(0, NULL); 350*7c478bd9Sstevel@tonic-gate } 351*7c478bd9Sstevel@tonic-gate if (*argv != NULL) { 352*7c478bd9Sstevel@tonic-gate switch (keyword(*argv)) { 353*7c478bd9Sstevel@tonic-gate case K_GET: 354*7c478bd9Sstevel@tonic-gate case K_CHANGE: 355*7c478bd9Sstevel@tonic-gate case K_ADD: 356*7c478bd9Sstevel@tonic-gate case K_DELETE: 357*7c478bd9Sstevel@tonic-gate return (newroute(argc, argv)); 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate case K_MONITOR: 360*7c478bd9Sstevel@tonic-gate rtmonitor(argc, argv); 361*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate case K_FLUSH: 364*7c478bd9Sstevel@tonic-gate flushroutes(argc, argv); 365*7c478bd9Sstevel@tonic-gate exit(0); 366*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 367*7c478bd9Sstevel@tonic-gate } 368*7c478bd9Sstevel@tonic-gate } 369*7c478bd9Sstevel@tonic-gate if (!fflag) 370*7c478bd9Sstevel@tonic-gate usage(*argv); 371*7c478bd9Sstevel@tonic-gate return (0); 372*7c478bd9Sstevel@tonic-gate } 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate /* 375*7c478bd9Sstevel@tonic-gate * Purge all entries in the routing tables not 376*7c478bd9Sstevel@tonic-gate * associated with network interfaces. 377*7c478bd9Sstevel@tonic-gate */ 378*7c478bd9Sstevel@tonic-gate void 379*7c478bd9Sstevel@tonic-gate flushroutes(int argc, char *argv[]) 380*7c478bd9Sstevel@tonic-gate { 381*7c478bd9Sstevel@tonic-gate int seqno; 382*7c478bd9Sstevel@tonic-gate int sd; /* mib stream */ 383*7c478bd9Sstevel@tonic-gate mib_item_t *item; 384*7c478bd9Sstevel@tonic-gate mib2_ipRouteEntry_t *rp; 385*7c478bd9Sstevel@tonic-gate mib2_ipv6RouteEntry_t *rp6; 386*7c478bd9Sstevel@tonic-gate int oerrno; 387*7c478bd9Sstevel@tonic-gate int off = 0; 388*7c478bd9Sstevel@tonic-gate int on = 1; 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off, 391*7c478bd9Sstevel@tonic-gate sizeof (off)) < 0) 392*7c478bd9Sstevel@tonic-gate quit("setsockopt", errno); 393*7c478bd9Sstevel@tonic-gate if (argc > 1) { 394*7c478bd9Sstevel@tonic-gate argv++; 395*7c478bd9Sstevel@tonic-gate if (argc == 2 && **argv == '-') { 396*7c478bd9Sstevel@tonic-gate /* 397*7c478bd9Sstevel@tonic-gate * The address family (preceded by a dash) may be used 398*7c478bd9Sstevel@tonic-gate * to flush the routes of that particular family. 399*7c478bd9Sstevel@tonic-gate */ 400*7c478bd9Sstevel@tonic-gate switch (keyword(*argv + 1)) { 401*7c478bd9Sstevel@tonic-gate case K_INET: 402*7c478bd9Sstevel@tonic-gate af = AF_INET; 403*7c478bd9Sstevel@tonic-gate break; 404*7c478bd9Sstevel@tonic-gate case K_LINK: 405*7c478bd9Sstevel@tonic-gate af = AF_LINK; 406*7c478bd9Sstevel@tonic-gate break; 407*7c478bd9Sstevel@tonic-gate case K_INET6: 408*7c478bd9Sstevel@tonic-gate af = AF_INET6; 409*7c478bd9Sstevel@tonic-gate break; 410*7c478bd9Sstevel@tonic-gate default: 411*7c478bd9Sstevel@tonic-gate usage(*argv); 412*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate } else { 415*7c478bd9Sstevel@tonic-gate usage(*argv); 416*7c478bd9Sstevel@tonic-gate } 417*7c478bd9Sstevel@tonic-gate } 418*7c478bd9Sstevel@tonic-gate sd = open("/dev/ip", O_RDWR); 419*7c478bd9Sstevel@tonic-gate oerrno = errno; 420*7c478bd9Sstevel@tonic-gate if (sd < 0) { 421*7c478bd9Sstevel@tonic-gate switch (errno) { 422*7c478bd9Sstevel@tonic-gate case EACCES: 423*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 424*7c478bd9Sstevel@tonic-gate gettext("route: flush: insufficient privileges\n")); 425*7c478bd9Sstevel@tonic-gate exit(oerrno); 426*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 427*7c478bd9Sstevel@tonic-gate default: 428*7c478bd9Sstevel@tonic-gate quit(gettext("can't open mib stream"), oerrno); 429*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate if ((item = mibget(sd)) == NULL) 433*7c478bd9Sstevel@tonic-gate quit("mibget", errno); 434*7c478bd9Sstevel@tonic-gate if (verbose) { 435*7c478bd9Sstevel@tonic-gate (void) printf("Examining routing table from " 436*7c478bd9Sstevel@tonic-gate "T_SVR4_OPTMGMT_REQ\n"); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate seqno = 0; /* ??? */ 439*7c478bd9Sstevel@tonic-gate switch (af) { 440*7c478bd9Sstevel@tonic-gate case AF_INET: 441*7c478bd9Sstevel@tonic-gate /* Extract ipRouteEntrySize */ 442*7c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 443*7c478bd9Sstevel@tonic-gate if (item->mib_id != 0) 444*7c478bd9Sstevel@tonic-gate continue; 445*7c478bd9Sstevel@tonic-gate if (item->group == MIB2_IP) { 446*7c478bd9Sstevel@tonic-gate ipRouteEntrySize = 447*7c478bd9Sstevel@tonic-gate ((mib2_ip_t *)item->valp)->ipRouteEntrySize; 448*7c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(ipRouteEntrySize, 449*7c478bd9Sstevel@tonic-gate sizeof (mib2_ipRouteEntry_t *))); 450*7c478bd9Sstevel@tonic-gate break; 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate } 453*7c478bd9Sstevel@tonic-gate if (ipRouteEntrySize == 0) { 454*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 455*7c478bd9Sstevel@tonic-gate gettext("ipRouteEntrySize can't be determined.\n")); 456*7c478bd9Sstevel@tonic-gate exit(1); 457*7c478bd9Sstevel@tonic-gate } 458*7c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 459*7c478bd9Sstevel@tonic-gate /* 460*7c478bd9Sstevel@tonic-gate * skip all the other trash that comes up the mib stream 461*7c478bd9Sstevel@tonic-gate */ 462*7c478bd9Sstevel@tonic-gate if (item->group != MIB2_IP || 463*7c478bd9Sstevel@tonic-gate item->mib_id != MIB2_IP_ROUTE) 464*7c478bd9Sstevel@tonic-gate continue; 465*7c478bd9Sstevel@tonic-gate for (rp = (mib2_ipRouteEntry_t *)item->valp; 466*7c478bd9Sstevel@tonic-gate (char *)rp < (char *)item->valp + item->length; 467*7c478bd9Sstevel@tonic-gate /* LINTED */ 468*7c478bd9Sstevel@tonic-gate rp = (mib2_ipRouteEntry_t *) 469*7c478bd9Sstevel@tonic-gate ((char *)rp + ipRouteEntrySize)) { 470*7c478bd9Sstevel@tonic-gate delRouteEntry(rp, NULL, seqno); 471*7c478bd9Sstevel@tonic-gate seqno++; 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate break; 474*7c478bd9Sstevel@tonic-gate } 475*7c478bd9Sstevel@tonic-gate break; 476*7c478bd9Sstevel@tonic-gate case AF_INET6: 477*7c478bd9Sstevel@tonic-gate /* Extract ipv6RouteEntrySize */ 478*7c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 479*7c478bd9Sstevel@tonic-gate if (item->mib_id != 0) 480*7c478bd9Sstevel@tonic-gate continue; 481*7c478bd9Sstevel@tonic-gate if (item->group == MIB2_IP6) { 482*7c478bd9Sstevel@tonic-gate ipv6RouteEntrySize = 483*7c478bd9Sstevel@tonic-gate ((mib2_ipv6IfStatsEntry_t *)item->valp)-> 484*7c478bd9Sstevel@tonic-gate ipv6RouteEntrySize; 485*7c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(ipv6RouteEntrySize, 486*7c478bd9Sstevel@tonic-gate sizeof (mib2_ipv6RouteEntry_t *))); 487*7c478bd9Sstevel@tonic-gate break; 488*7c478bd9Sstevel@tonic-gate } 489*7c478bd9Sstevel@tonic-gate } 490*7c478bd9Sstevel@tonic-gate if (ipv6RouteEntrySize == 0) { 491*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 492*7c478bd9Sstevel@tonic-gate "ipv6RouteEntrySize cannot be determined.\n")); 493*7c478bd9Sstevel@tonic-gate exit(1); 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 496*7c478bd9Sstevel@tonic-gate /* 497*7c478bd9Sstevel@tonic-gate * skip all the other trash that comes up the mib stream 498*7c478bd9Sstevel@tonic-gate */ 499*7c478bd9Sstevel@tonic-gate if (item->group != MIB2_IP6 || 500*7c478bd9Sstevel@tonic-gate item->mib_id != MIB2_IP6_ROUTE) 501*7c478bd9Sstevel@tonic-gate continue; 502*7c478bd9Sstevel@tonic-gate for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp; 503*7c478bd9Sstevel@tonic-gate (char *)rp6 < (char *)item->valp + item->length; 504*7c478bd9Sstevel@tonic-gate /* LINTED */ 505*7c478bd9Sstevel@tonic-gate rp6 = (mib2_ipv6RouteEntry_t *) 506*7c478bd9Sstevel@tonic-gate ((char *)rp6 + ipv6RouteEntrySize)) { 507*7c478bd9Sstevel@tonic-gate delRouteEntry(NULL, rp6, seqno); 508*7c478bd9Sstevel@tonic-gate seqno++; 509*7c478bd9Sstevel@tonic-gate } 510*7c478bd9Sstevel@tonic-gate break; 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate break; 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, 516*7c478bd9Sstevel@tonic-gate sizeof (on)) < 0) 517*7c478bd9Sstevel@tonic-gate quit("setsockopt", errno); 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate /* 521*7c478bd9Sstevel@tonic-gate * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or 522*7c478bd9Sstevel@tonic-gate * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in 523*7c478bd9Sstevel@tonic-gate * order to facilitate the flushing of RTF_GATEWAY routes. 524*7c478bd9Sstevel@tonic-gate */ 525*7c478bd9Sstevel@tonic-gate static void 526*7c478bd9Sstevel@tonic-gate delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno) 527*7c478bd9Sstevel@tonic-gate { 528*7c478bd9Sstevel@tonic-gate char *cp; 529*7c478bd9Sstevel@tonic-gate int ire_type; 530*7c478bd9Sstevel@tonic-gate int rlen; 531*7c478bd9Sstevel@tonic-gate struct rt_msghdr *rtm; 532*7c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 533*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 534*7c478bd9Sstevel@tonic-gate int slen; 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate if (rp != NULL) 537*7c478bd9Sstevel@tonic-gate ire_type = rp->ipRouteInfo.re_ire_type; 538*7c478bd9Sstevel@tonic-gate else 539*7c478bd9Sstevel@tonic-gate ire_type = rp6->ipv6RouteInfo.re_ire_type; 540*7c478bd9Sstevel@tonic-gate if (ire_type != IRE_DEFAULT && 541*7c478bd9Sstevel@tonic-gate ire_type != IRE_PREFIX && 542*7c478bd9Sstevel@tonic-gate ire_type != IRE_HOST && 543*7c478bd9Sstevel@tonic-gate ire_type != IRE_HOST_REDIRECT) 544*7c478bd9Sstevel@tonic-gate return; 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate rtm = &m_rtmsg.m_rtm; 547*7c478bd9Sstevel@tonic-gate (void) memset(rtm, 0, sizeof (m_rtmsg)); 548*7c478bd9Sstevel@tonic-gate rtm->rtm_type = RTM_DELETE; 549*7c478bd9Sstevel@tonic-gate rtm->rtm_seq = seqno; 550*7c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_GATEWAY; 551*7c478bd9Sstevel@tonic-gate rtm->rtm_version = RTM_VERSION; 552*7c478bd9Sstevel@tonic-gate rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 553*7c478bd9Sstevel@tonic-gate cp = m_rtmsg.m_space; 554*7c478bd9Sstevel@tonic-gate if (rp != NULL) { 555*7c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in); 556*7c478bd9Sstevel@tonic-gate if (rp->ipRouteMask == IP_HOST_MASK) 557*7c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_HOST; 558*7c478bd9Sstevel@tonic-gate (void) memset(&sin, 0, slen); 559*7c478bd9Sstevel@tonic-gate sin.sin_family = AF_INET; 560*7c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteDest; 561*7c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 562*7c478bd9Sstevel@tonic-gate cp += slen; 563*7c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteNextHop; 564*7c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 565*7c478bd9Sstevel@tonic-gate cp += slen; 566*7c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteMask; 567*7c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 568*7c478bd9Sstevel@tonic-gate cp += slen; 569*7c478bd9Sstevel@tonic-gate } else { 570*7c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in6); 571*7c478bd9Sstevel@tonic-gate if (rp6->ipv6RoutePfxLength == IPV6_ABITS) 572*7c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_HOST; 573*7c478bd9Sstevel@tonic-gate (void) memset(&sin6, 0, slen); 574*7c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 575*7c478bd9Sstevel@tonic-gate sin6.sin6_addr = rp6->ipv6RouteDest; 576*7c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 577*7c478bd9Sstevel@tonic-gate cp += slen; 578*7c478bd9Sstevel@tonic-gate sin6.sin6_addr = rp6->ipv6RouteNextHop; 579*7c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 580*7c478bd9Sstevel@tonic-gate cp += slen; 581*7c478bd9Sstevel@tonic-gate (void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr)); 582*7c478bd9Sstevel@tonic-gate (void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS, 583*7c478bd9Sstevel@tonic-gate (uchar_t *)&sin6.sin6_addr.s6_addr); 584*7c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 585*7c478bd9Sstevel@tonic-gate cp += slen; 586*7c478bd9Sstevel@tonic-gate } 587*7c478bd9Sstevel@tonic-gate rtm->rtm_msglen = cp - (char *)&m_rtmsg; 588*7c478bd9Sstevel@tonic-gate if (debugonly) { 589*7c478bd9Sstevel@tonic-gate /* 590*7c478bd9Sstevel@tonic-gate * In debugonly mode, the routing socket message to delete the 591*7c478bd9Sstevel@tonic-gate * current entry is not actually sent. However if verbose is 592*7c478bd9Sstevel@tonic-gate * also set, the routing socket message that would have been 593*7c478bd9Sstevel@tonic-gate * is printed. 594*7c478bd9Sstevel@tonic-gate */ 595*7c478bd9Sstevel@tonic-gate if (verbose) 596*7c478bd9Sstevel@tonic-gate print_rtmsg(rtm, rtm->rtm_msglen); 597*7c478bd9Sstevel@tonic-gate return; 598*7c478bd9Sstevel@tonic-gate } 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen); 601*7c478bd9Sstevel@tonic-gate if (rlen < (int)rtm->rtm_msglen) { 602*7c478bd9Sstevel@tonic-gate if (rlen < 0) { 603*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 604*7c478bd9Sstevel@tonic-gate gettext("route: write to routing socket: %s\n"), 605*7c478bd9Sstevel@tonic-gate strerror(errno)); 606*7c478bd9Sstevel@tonic-gate } else { 607*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: write to " 608*7c478bd9Sstevel@tonic-gate "routing socket got only %d for rlen\n"), rlen); 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate return; 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate if (qflag) { 613*7c478bd9Sstevel@tonic-gate /* 614*7c478bd9Sstevel@tonic-gate * In quiet mode, nothing is printed at all (unless the write() 615*7c478bd9Sstevel@tonic-gate * itself failed. 616*7c478bd9Sstevel@tonic-gate */ 617*7c478bd9Sstevel@tonic-gate return; 618*7c478bd9Sstevel@tonic-gate } 619*7c478bd9Sstevel@tonic-gate if (verbose) { 620*7c478bd9Sstevel@tonic-gate print_rtmsg(rtm, rlen); 621*7c478bd9Sstevel@tonic-gate } else { 622*7c478bd9Sstevel@tonic-gate struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate (void) printf("%-20.20s ", 625*7c478bd9Sstevel@tonic-gate rtm->rtm_flags & RTF_HOST ? routename(sa) : 626*7c478bd9Sstevel@tonic-gate netname(sa)); 627*7c478bd9Sstevel@tonic-gate /* LINTED */ 628*7c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)(salen(sa) + (char *)sa); 629*7c478bd9Sstevel@tonic-gate (void) printf("%-20.20s ", routename(sa)); 630*7c478bd9Sstevel@tonic-gate (void) printf("done\n"); 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate /* 635*7c478bd9Sstevel@tonic-gate * Return the name of the host whose address is given. 636*7c478bd9Sstevel@tonic-gate */ 637*7c478bd9Sstevel@tonic-gate char * 638*7c478bd9Sstevel@tonic-gate routename(struct sockaddr *sa) 639*7c478bd9Sstevel@tonic-gate { 640*7c478bd9Sstevel@tonic-gate char *cp; 641*7c478bd9Sstevel@tonic-gate static char line[MAXHOSTNAMELEN + 1]; 642*7c478bd9Sstevel@tonic-gate struct hostent *hp = NULL; 643*7c478bd9Sstevel@tonic-gate static char domain[MAXHOSTNAMELEN + 1]; 644*7c478bd9Sstevel@tonic-gate static boolean_t first = B_TRUE; 645*7c478bd9Sstevel@tonic-gate struct in_addr in; 646*7c478bd9Sstevel@tonic-gate struct in6_addr in6; 647*7c478bd9Sstevel@tonic-gate int error_num; 648*7c478bd9Sstevel@tonic-gate ushort_t *s; 649*7c478bd9Sstevel@tonic-gate ushort_t *slim; 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate if (first) { 652*7c478bd9Sstevel@tonic-gate first = B_FALSE; 653*7c478bd9Sstevel@tonic-gate if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 654*7c478bd9Sstevel@tonic-gate (cp = strchr(domain, '.'))) 655*7c478bd9Sstevel@tonic-gate (void) strcpy(domain, cp + 1); 656*7c478bd9Sstevel@tonic-gate else 657*7c478bd9Sstevel@tonic-gate domain[0] = 0; 658*7c478bd9Sstevel@tonic-gate } 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate if (salen(sa) == 0) { 661*7c478bd9Sstevel@tonic-gate (void) strcpy(line, "default"); 662*7c478bd9Sstevel@tonic-gate return (line); 663*7c478bd9Sstevel@tonic-gate } 664*7c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 665*7c478bd9Sstevel@tonic-gate 666*7c478bd9Sstevel@tonic-gate case AF_INET: 667*7c478bd9Sstevel@tonic-gate /* LINTED */ 668*7c478bd9Sstevel@tonic-gate in = ((struct sockaddr_in *)sa)->sin_addr; 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate cp = NULL; 671*7c478bd9Sstevel@tonic-gate if (in.s_addr == INADDR_ANY) 672*7c478bd9Sstevel@tonic-gate cp = "default"; 673*7c478bd9Sstevel@tonic-gate if (cp == NULL && !nflag) { 674*7c478bd9Sstevel@tonic-gate hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 675*7c478bd9Sstevel@tonic-gate AF_INET); 676*7c478bd9Sstevel@tonic-gate if (hp != NULL) { 677*7c478bd9Sstevel@tonic-gate if (((cp = strchr(hp->h_name, '.')) != NULL) && 678*7c478bd9Sstevel@tonic-gate (strcmp(cp + 1, domain) == 0)) 679*7c478bd9Sstevel@tonic-gate *cp = 0; 680*7c478bd9Sstevel@tonic-gate cp = hp->h_name; 681*7c478bd9Sstevel@tonic-gate } 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate if (cp != NULL) { 684*7c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 685*7c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 686*7c478bd9Sstevel@tonic-gate } else { 687*7c478bd9Sstevel@tonic-gate in.s_addr = ntohl(in.s_addr); 688*7c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 689*7c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8), 690*7c478bd9Sstevel@tonic-gate C(in.s_addr)); 691*7c478bd9Sstevel@tonic-gate } 692*7c478bd9Sstevel@tonic-gate break; 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate case AF_LINK: 695*7c478bd9Sstevel@tonic-gate return (link_ntoa((struct sockaddr_dl *)sa)); 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate case AF_INET6: 698*7c478bd9Sstevel@tonic-gate /* LINTED */ 699*7c478bd9Sstevel@tonic-gate in6 = ((struct sockaddr_in6 *)sa)->sin6_addr; 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate cp = NULL; 702*7c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&in6)) 703*7c478bd9Sstevel@tonic-gate cp = "default"; 704*7c478bd9Sstevel@tonic-gate if (cp == NULL && !nflag) { 705*7c478bd9Sstevel@tonic-gate hp = getipnodebyaddr((char *)&in6, 706*7c478bd9Sstevel@tonic-gate sizeof (struct in6_addr), AF_INET6, &error_num); 707*7c478bd9Sstevel@tonic-gate if (hp != NULL) { 708*7c478bd9Sstevel@tonic-gate if (((cp = strchr(hp->h_name, '.')) != NULL) && 709*7c478bd9Sstevel@tonic-gate (strcmp(cp + 1, domain) == 0)) 710*7c478bd9Sstevel@tonic-gate *cp = 0; 711*7c478bd9Sstevel@tonic-gate cp = hp->h_name; 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate } 714*7c478bd9Sstevel@tonic-gate if (cp != NULL) { 715*7c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 716*7c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 717*7c478bd9Sstevel@tonic-gate } else { 718*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&in6, line, 719*7c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN); 720*7c478bd9Sstevel@tonic-gate } 721*7c478bd9Sstevel@tonic-gate if (hp != NULL) 722*7c478bd9Sstevel@tonic-gate freehostent(hp); 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate break; 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate default: 727*7c478bd9Sstevel@tonic-gate s = (ushort_t *)sa; 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate slim = s + ((salen(sa) + 1) >> 1); 730*7c478bd9Sstevel@tonic-gate cp = line + sprintf(line, "(%d)", sa->sa_family); 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate while (++s < slim) /* start with sa->sa_data */ 733*7c478bd9Sstevel@tonic-gate cp += sprintf(cp, " %x", *s); 734*7c478bd9Sstevel@tonic-gate break; 735*7c478bd9Sstevel@tonic-gate } 736*7c478bd9Sstevel@tonic-gate return (line); 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate /* 740*7c478bd9Sstevel@tonic-gate * Return the name of the network whose address is given. 741*7c478bd9Sstevel@tonic-gate * The address is assumed to be that of a net or subnet, not a host. 742*7c478bd9Sstevel@tonic-gate */ 743*7c478bd9Sstevel@tonic-gate static char * 744*7c478bd9Sstevel@tonic-gate netname(struct sockaddr *sa) 745*7c478bd9Sstevel@tonic-gate { 746*7c478bd9Sstevel@tonic-gate char *cp = NULL; 747*7c478bd9Sstevel@tonic-gate static char line[MAXHOSTNAMELEN + 1]; 748*7c478bd9Sstevel@tonic-gate struct netent *np; 749*7c478bd9Sstevel@tonic-gate in_addr_t net, mask; 750*7c478bd9Sstevel@tonic-gate int subnetshift; 751*7c478bd9Sstevel@tonic-gate struct in_addr in; 752*7c478bd9Sstevel@tonic-gate ushort_t *s; 753*7c478bd9Sstevel@tonic-gate ushort_t *slim; 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 756*7c478bd9Sstevel@tonic-gate 757*7c478bd9Sstevel@tonic-gate case AF_INET: 758*7c478bd9Sstevel@tonic-gate /* LINTED */ 759*7c478bd9Sstevel@tonic-gate in = ((struct sockaddr_in *)sa)->sin_addr; 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate in.s_addr = ntohl(in.s_addr); 762*7c478bd9Sstevel@tonic-gate if (in.s_addr == INADDR_ANY) { 763*7c478bd9Sstevel@tonic-gate cp = "default"; 764*7c478bd9Sstevel@tonic-gate } else if (!nflag) { 765*7c478bd9Sstevel@tonic-gate if (IN_CLASSA(in.s_addr)) { 766*7c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 767*7c478bd9Sstevel@tonic-gate subnetshift = 8; 768*7c478bd9Sstevel@tonic-gate } else if (IN_CLASSB(in.s_addr)) { 769*7c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 770*7c478bd9Sstevel@tonic-gate subnetshift = 8; 771*7c478bd9Sstevel@tonic-gate } else { 772*7c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 773*7c478bd9Sstevel@tonic-gate subnetshift = 4; 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate /* 776*7c478bd9Sstevel@tonic-gate * If there are more bits than the standard mask 777*7c478bd9Sstevel@tonic-gate * would suggest, subnets must be in use. 778*7c478bd9Sstevel@tonic-gate * Guess at the subnet mask, assuming reasonable 779*7c478bd9Sstevel@tonic-gate * width subnet fields. 780*7c478bd9Sstevel@tonic-gate */ 781*7c478bd9Sstevel@tonic-gate while (in.s_addr &~ mask) 782*7c478bd9Sstevel@tonic-gate mask = (long)mask >> subnetshift; 783*7c478bd9Sstevel@tonic-gate net = in.s_addr & mask; 784*7c478bd9Sstevel@tonic-gate while ((mask & 1) == 0) 785*7c478bd9Sstevel@tonic-gate mask >>= 1, net >>= 1; 786*7c478bd9Sstevel@tonic-gate np = getnetbyaddr(net, AF_INET); 787*7c478bd9Sstevel@tonic-gate if (np != NULL) 788*7c478bd9Sstevel@tonic-gate cp = np->n_name; 789*7c478bd9Sstevel@tonic-gate } 790*7c478bd9Sstevel@tonic-gate if (cp != NULL) { 791*7c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 792*7c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 793*7c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xffffff) == 0) { 794*7c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u", C(in.s_addr >> 24)); 795*7c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xffff) == 0) { 796*7c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 797*7c478bd9Sstevel@tonic-gate C(in.s_addr >> 16)); 798*7c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xff) == 0) { 799*7c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 800*7c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8)); 801*7c478bd9Sstevel@tonic-gate } else { 802*7c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 803*7c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8), 804*7c478bd9Sstevel@tonic-gate C(in.s_addr)); 805*7c478bd9Sstevel@tonic-gate } 806*7c478bd9Sstevel@tonic-gate break; 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate case AF_LINK: 809*7c478bd9Sstevel@tonic-gate return (link_ntoa((struct sockaddr_dl *)sa)); 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate case AF_INET6: 812*7c478bd9Sstevel@tonic-gate return (routename(sa)); 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate default: 815*7c478bd9Sstevel@tonic-gate /* LINTED */ 816*7c478bd9Sstevel@tonic-gate s = (ushort_t *)sa->sa_data; 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate slim = s + ((salen(sa) + 1) >> 1); 819*7c478bd9Sstevel@tonic-gate cp = line + sprintf(line, "af %d:", sa->sa_family); 820*7c478bd9Sstevel@tonic-gate 821*7c478bd9Sstevel@tonic-gate while (s < slim) 822*7c478bd9Sstevel@tonic-gate cp += sprintf(cp, " %x", *s++); 823*7c478bd9Sstevel@tonic-gate break; 824*7c478bd9Sstevel@tonic-gate } 825*7c478bd9Sstevel@tonic-gate return (line); 826*7c478bd9Sstevel@tonic-gate } 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate void 829*7c478bd9Sstevel@tonic-gate set_metric(char *value, int key) 830*7c478bd9Sstevel@tonic-gate { 831*7c478bd9Sstevel@tonic-gate int flag = 0; 832*7c478bd9Sstevel@tonic-gate uint_t noval, *valp = &noval; 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate switch (key) { 835*7c478bd9Sstevel@tonic-gate #define caseof(x, y, z) case (x): valp = &rt_metrics.z; flag = (y); break 836*7c478bd9Sstevel@tonic-gate caseof(K_MTU, RTV_MTU, rmx_mtu); 837*7c478bd9Sstevel@tonic-gate caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 838*7c478bd9Sstevel@tonic-gate caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 839*7c478bd9Sstevel@tonic-gate caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 840*7c478bd9Sstevel@tonic-gate caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 841*7c478bd9Sstevel@tonic-gate caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 842*7c478bd9Sstevel@tonic-gate caseof(K_RTT, RTV_RTT, rmx_rtt); 843*7c478bd9Sstevel@tonic-gate caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 844*7c478bd9Sstevel@tonic-gate #undef caseof 845*7c478bd9Sstevel@tonic-gate } 846*7c478bd9Sstevel@tonic-gate rtm_inits |= flag; 847*7c478bd9Sstevel@tonic-gate if (lockrest || locking) 848*7c478bd9Sstevel@tonic-gate rt_metrics.rmx_locks |= flag; 849*7c478bd9Sstevel@tonic-gate if (locking) 850*7c478bd9Sstevel@tonic-gate locking = B_FALSE; 851*7c478bd9Sstevel@tonic-gate *valp = atoi(value); 852*7c478bd9Sstevel@tonic-gate } 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate int 855*7c478bd9Sstevel@tonic-gate newroute(int argc, char **argv) 856*7c478bd9Sstevel@tonic-gate { 857*7c478bd9Sstevel@tonic-gate char *cmd, *dest = "", *gateway = "", *err; 858*7c478bd9Sstevel@tonic-gate boolean_t ishost = B_FALSE; 859*7c478bd9Sstevel@tonic-gate int ret, attempts, oerrno, flags = RTF_STATIC; 860*7c478bd9Sstevel@tonic-gate int key; 861*7c478bd9Sstevel@tonic-gate struct hostent *hp = NULL; 862*7c478bd9Sstevel@tonic-gate static char obuf[INET6_ADDRSTRLEN]; 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate cmd = argv[0]; 865*7c478bd9Sstevel@tonic-gate if (*cmd != 'g' && !tflag) { 866*7c478bd9Sstevel@tonic-gate /* Don't want to read back our messages */ 867*7c478bd9Sstevel@tonic-gate (void) shutdown(s, 0); 868*7c478bd9Sstevel@tonic-gate } 869*7c478bd9Sstevel@tonic-gate while (--argc > 0) { 870*7c478bd9Sstevel@tonic-gate key = keyword(*(++argv)); 871*7c478bd9Sstevel@tonic-gate if (key == K_HOST) { 872*7c478bd9Sstevel@tonic-gate forcehost = B_TRUE; 873*7c478bd9Sstevel@tonic-gate } else if (key == K_NET) { 874*7c478bd9Sstevel@tonic-gate forcenet = B_TRUE; 875*7c478bd9Sstevel@tonic-gate } else if (**(argv) == '-') { 876*7c478bd9Sstevel@tonic-gate switch (key = keyword(1 + *argv)) { 877*7c478bd9Sstevel@tonic-gate case K_LINK: 878*7c478bd9Sstevel@tonic-gate af = AF_LINK; 879*7c478bd9Sstevel@tonic-gate break; 880*7c478bd9Sstevel@tonic-gate case K_INET: 881*7c478bd9Sstevel@tonic-gate af = AF_INET; 882*7c478bd9Sstevel@tonic-gate break; 883*7c478bd9Sstevel@tonic-gate case K_SA: 884*7c478bd9Sstevel@tonic-gate af = PF_ROUTE; 885*7c478bd9Sstevel@tonic-gate break; 886*7c478bd9Sstevel@tonic-gate case K_INET6: 887*7c478bd9Sstevel@tonic-gate af = AF_INET6; 888*7c478bd9Sstevel@tonic-gate break; 889*7c478bd9Sstevel@tonic-gate case K_IFACE: 890*7c478bd9Sstevel@tonic-gate case K_INTERFACE: 891*7c478bd9Sstevel@tonic-gate iflag = B_TRUE; 892*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 893*7c478bd9Sstevel@tonic-gate case K_NOSTATIC: 894*7c478bd9Sstevel@tonic-gate flags &= ~RTF_STATIC; 895*7c478bd9Sstevel@tonic-gate break; 896*7c478bd9Sstevel@tonic-gate case K_LOCK: 897*7c478bd9Sstevel@tonic-gate locking = B_TRUE; 898*7c478bd9Sstevel@tonic-gate break; 899*7c478bd9Sstevel@tonic-gate case K_LOCKREST: 900*7c478bd9Sstevel@tonic-gate lockrest = B_TRUE; 901*7c478bd9Sstevel@tonic-gate break; 902*7c478bd9Sstevel@tonic-gate case K_HOST: 903*7c478bd9Sstevel@tonic-gate forcehost = B_TRUE; 904*7c478bd9Sstevel@tonic-gate break; 905*7c478bd9Sstevel@tonic-gate case K_REJECT: 906*7c478bd9Sstevel@tonic-gate flags |= RTF_REJECT; 907*7c478bd9Sstevel@tonic-gate break; 908*7c478bd9Sstevel@tonic-gate case K_BLACKHOLE: 909*7c478bd9Sstevel@tonic-gate flags |= RTF_BLACKHOLE; 910*7c478bd9Sstevel@tonic-gate break; 911*7c478bd9Sstevel@tonic-gate case K_PROTO1: 912*7c478bd9Sstevel@tonic-gate flags |= RTF_PROTO1; 913*7c478bd9Sstevel@tonic-gate break; 914*7c478bd9Sstevel@tonic-gate case K_PROTO2: 915*7c478bd9Sstevel@tonic-gate flags |= RTF_PROTO2; 916*7c478bd9Sstevel@tonic-gate break; 917*7c478bd9Sstevel@tonic-gate case K_CLONING: 918*7c478bd9Sstevel@tonic-gate flags |= RTF_CLONING; 919*7c478bd9Sstevel@tonic-gate break; 920*7c478bd9Sstevel@tonic-gate case K_XRESOLVE: 921*7c478bd9Sstevel@tonic-gate flags |= RTF_XRESOLVE; 922*7c478bd9Sstevel@tonic-gate break; 923*7c478bd9Sstevel@tonic-gate case K_STATIC: 924*7c478bd9Sstevel@tonic-gate flags |= RTF_STATIC; 925*7c478bd9Sstevel@tonic-gate break; 926*7c478bd9Sstevel@tonic-gate case K_IFA: 927*7c478bd9Sstevel@tonic-gate argc--; 928*7c478bd9Sstevel@tonic-gate (void) getaddr(RTA_IFA, *++argv, NULL); 929*7c478bd9Sstevel@tonic-gate break; 930*7c478bd9Sstevel@tonic-gate case K_IFP: 931*7c478bd9Sstevel@tonic-gate argc--; 932*7c478bd9Sstevel@tonic-gate (void) getaddr(RTA_IFP, *++argv, NULL); 933*7c478bd9Sstevel@tonic-gate break; 934*7c478bd9Sstevel@tonic-gate case K_GATEWAY: 935*7c478bd9Sstevel@tonic-gate /* 936*7c478bd9Sstevel@tonic-gate * For the gateway parameter, retrieve the 937*7c478bd9Sstevel@tonic-gate * pointer to the struct hostent so that all 938*7c478bd9Sstevel@tonic-gate * possible addresses can be tried until one 939*7c478bd9Sstevel@tonic-gate * is successful. 940*7c478bd9Sstevel@tonic-gate */ 941*7c478bd9Sstevel@tonic-gate argc--; 942*7c478bd9Sstevel@tonic-gate gateway = *++argv; 943*7c478bd9Sstevel@tonic-gate (void) getaddr(RTA_GATEWAY, *argv, &hp); 944*7c478bd9Sstevel@tonic-gate break; 945*7c478bd9Sstevel@tonic-gate case K_DST: 946*7c478bd9Sstevel@tonic-gate argc--; 947*7c478bd9Sstevel@tonic-gate ishost = getaddr(RTA_DST, *++argv, NULL); 948*7c478bd9Sstevel@tonic-gate dest = *argv; 949*7c478bd9Sstevel@tonic-gate break; 950*7c478bd9Sstevel@tonic-gate case K_NETMASK: 951*7c478bd9Sstevel@tonic-gate argc--; 952*7c478bd9Sstevel@tonic-gate (void) getaddr(RTA_NETMASK, *++argv, NULL); 953*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 954*7c478bd9Sstevel@tonic-gate case K_NET: 955*7c478bd9Sstevel@tonic-gate forcenet = B_TRUE; 956*7c478bd9Sstevel@tonic-gate break; 957*7c478bd9Sstevel@tonic-gate case K_MTU: 958*7c478bd9Sstevel@tonic-gate case K_HOPCOUNT: 959*7c478bd9Sstevel@tonic-gate case K_EXPIRE: 960*7c478bd9Sstevel@tonic-gate case K_RECVPIPE: 961*7c478bd9Sstevel@tonic-gate case K_SENDPIPE: 962*7c478bd9Sstevel@tonic-gate case K_SSTHRESH: 963*7c478bd9Sstevel@tonic-gate case K_RTT: 964*7c478bd9Sstevel@tonic-gate case K_RTTVAR: 965*7c478bd9Sstevel@tonic-gate argc--; 966*7c478bd9Sstevel@tonic-gate set_metric(*++argv, key); 967*7c478bd9Sstevel@tonic-gate break; 968*7c478bd9Sstevel@tonic-gate case K_PRIVATE: 969*7c478bd9Sstevel@tonic-gate flags |= RTF_PRIVATE; 970*7c478bd9Sstevel@tonic-gate break; 971*7c478bd9Sstevel@tonic-gate case K_MULTIRT: 972*7c478bd9Sstevel@tonic-gate flags |= RTF_MULTIRT; 973*7c478bd9Sstevel@tonic-gate break; 974*7c478bd9Sstevel@tonic-gate case K_SETSRC: 975*7c478bd9Sstevel@tonic-gate argc--; 976*7c478bd9Sstevel@tonic-gate (void) getaddr(RTA_SRC, *++argv, NULL); 977*7c478bd9Sstevel@tonic-gate flags |= RTF_SETSRC; 978*7c478bd9Sstevel@tonic-gate break; 979*7c478bd9Sstevel@tonic-gate default: 980*7c478bd9Sstevel@tonic-gate usage(*argv + 1); 981*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 982*7c478bd9Sstevel@tonic-gate } 983*7c478bd9Sstevel@tonic-gate } else { 984*7c478bd9Sstevel@tonic-gate if ((rtm_addrs & RTA_DST) == 0) { 985*7c478bd9Sstevel@tonic-gate dest = *argv; 986*7c478bd9Sstevel@tonic-gate ishost = getaddr(RTA_DST, *argv, NULL); 987*7c478bd9Sstevel@tonic-gate } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 988*7c478bd9Sstevel@tonic-gate /* 989*7c478bd9Sstevel@tonic-gate * For the gateway parameter, retrieve the 990*7c478bd9Sstevel@tonic-gate * pointer to the struct hostent so that all 991*7c478bd9Sstevel@tonic-gate * possible addresses can be tried until one 992*7c478bd9Sstevel@tonic-gate * is successful. 993*7c478bd9Sstevel@tonic-gate */ 994*7c478bd9Sstevel@tonic-gate gateway = *argv; 995*7c478bd9Sstevel@tonic-gate (void) getaddr(RTA_GATEWAY, *argv, &hp); 996*7c478bd9Sstevel@tonic-gate } else { 997*7c478bd9Sstevel@tonic-gate ulong_t metric = strtoul(*argv, &err, 10); 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate /* 1000*7c478bd9Sstevel@tonic-gate * Assume that a regular number is a metric. 1001*7c478bd9Sstevel@tonic-gate * Needed for compatibility with old route 1002*7c478bd9Sstevel@tonic-gate * command syntax. 1003*7c478bd9Sstevel@tonic-gate */ 1004*7c478bd9Sstevel@tonic-gate if (*argv != err && *err == '\0' && 1005*7c478bd9Sstevel@tonic-gate metric < 0x80000000ul) { 1006*7c478bd9Sstevel@tonic-gate iflag = (metric == 0); 1007*7c478bd9Sstevel@tonic-gate if (verbose) { 1008*7c478bd9Sstevel@tonic-gate (void) printf("old usage of " 1009*7c478bd9Sstevel@tonic-gate "trailing number, assuming " 1010*7c478bd9Sstevel@tonic-gate "route %s\n", iflag ? 1011*7c478bd9Sstevel@tonic-gate "to if" : "via gateway"); 1012*7c478bd9Sstevel@tonic-gate } 1013*7c478bd9Sstevel@tonic-gate continue; 1014*7c478bd9Sstevel@tonic-gate } 1015*7c478bd9Sstevel@tonic-gate (void) getaddr(RTA_NETMASK, *argv, NULL); 1016*7c478bd9Sstevel@tonic-gate } 1017*7c478bd9Sstevel@tonic-gate } 1018*7c478bd9Sstevel@tonic-gate } 1019*7c478bd9Sstevel@tonic-gate if ((rtm_addrs & RTA_DST) == 0) { 1020*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1021*7c478bd9Sstevel@tonic-gate gettext("route: destination required following command\n")); 1022*7c478bd9Sstevel@tonic-gate usage((char *)NULL); 1023*7c478bd9Sstevel@tonic-gate } else if ((*cmd == 'a' || *cmd == 'd') && 1024*7c478bd9Sstevel@tonic-gate (rtm_addrs & RTA_GATEWAY) == 0) { 1025*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1026*7c478bd9Sstevel@tonic-gate gettext("route: gateway required for add or delete " 1027*7c478bd9Sstevel@tonic-gate "command\n")); 1028*7c478bd9Sstevel@tonic-gate usage((char *)NULL); 1029*7c478bd9Sstevel@tonic-gate } 1030*7c478bd9Sstevel@tonic-gate 1031*7c478bd9Sstevel@tonic-gate /* 1032*7c478bd9Sstevel@tonic-gate * If the netmask has been specified use it to determine RTF_HOST. 1033*7c478bd9Sstevel@tonic-gate * Otherwise rely on the "-net" and "-host" specifiers. 1034*7c478bd9Sstevel@tonic-gate * Final fallback is whether ot not any bits were set in the address 1035*7c478bd9Sstevel@tonic-gate * past the classful network component. 1036*7c478bd9Sstevel@tonic-gate */ 1037*7c478bd9Sstevel@tonic-gate if (rtm_addrs & RTA_NETMASK) { 1038*7c478bd9Sstevel@tonic-gate if ((af == AF_INET && 1039*7c478bd9Sstevel@tonic-gate so_mask.sin.sin_addr.s_addr == IP_HOST_MASK) || 1040*7c478bd9Sstevel@tonic-gate (af == AF_INET6 && masklen == IPV6_ABITS)) 1041*7c478bd9Sstevel@tonic-gate forcehost = B_TRUE; 1042*7c478bd9Sstevel@tonic-gate else 1043*7c478bd9Sstevel@tonic-gate forcenet = B_TRUE; 1044*7c478bd9Sstevel@tonic-gate } 1045*7c478bd9Sstevel@tonic-gate if (forcehost) 1046*7c478bd9Sstevel@tonic-gate ishost = B_TRUE; 1047*7c478bd9Sstevel@tonic-gate if (forcenet) 1048*7c478bd9Sstevel@tonic-gate ishost = B_FALSE; 1049*7c478bd9Sstevel@tonic-gate flags |= RTF_UP; 1050*7c478bd9Sstevel@tonic-gate if (ishost) 1051*7c478bd9Sstevel@tonic-gate flags |= RTF_HOST; 1052*7c478bd9Sstevel@tonic-gate if (!iflag) 1053*7c478bd9Sstevel@tonic-gate flags |= RTF_GATEWAY; 1054*7c478bd9Sstevel@tonic-gate for (attempts = 1; ; attempts++) { 1055*7c478bd9Sstevel@tonic-gate errno = 0; 1056*7c478bd9Sstevel@tonic-gate if ((ret = rtmsg(*cmd, flags)) == 0) 1057*7c478bd9Sstevel@tonic-gate break; 1058*7c478bd9Sstevel@tonic-gate if (errno != ENETUNREACH && errno != ESRCH) 1059*7c478bd9Sstevel@tonic-gate break; 1060*7c478bd9Sstevel@tonic-gate if (*gateway != '\0' && hp != NULL && 1061*7c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts] != NULL) { 1062*7c478bd9Sstevel@tonic-gate switch (af) { 1063*7c478bd9Sstevel@tonic-gate case AF_INET: 1064*7c478bd9Sstevel@tonic-gate (void) memmove(&so_gate.sin.sin_addr, 1065*7c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts], hp->h_length); 1066*7c478bd9Sstevel@tonic-gate continue; 1067*7c478bd9Sstevel@tonic-gate case AF_INET6: 1068*7c478bd9Sstevel@tonic-gate (void) memmove(&so_gate.sin6.sin6_addr, 1069*7c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts], hp->h_length); 1070*7c478bd9Sstevel@tonic-gate continue; 1071*7c478bd9Sstevel@tonic-gate } 1072*7c478bd9Sstevel@tonic-gate } 1073*7c478bd9Sstevel@tonic-gate break; 1074*7c478bd9Sstevel@tonic-gate } 1075*7c478bd9Sstevel@tonic-gate oerrno = errno; 1076*7c478bd9Sstevel@tonic-gate if (*cmd != 'g') { 1077*7c478bd9Sstevel@tonic-gate (void) printf("%s %s %s", cmd, ishost ? "host" : "net", dest); 1078*7c478bd9Sstevel@tonic-gate if (*gateway != '\0') { 1079*7c478bd9Sstevel@tonic-gate switch (af) { 1080*7c478bd9Sstevel@tonic-gate case AF_INET: 1081*7c478bd9Sstevel@tonic-gate if (nflag) { 1082*7c478bd9Sstevel@tonic-gate (void) printf(": gateway %s", 1083*7c478bd9Sstevel@tonic-gate inet_ntoa(so_gate.sin.sin_addr)); 1084*7c478bd9Sstevel@tonic-gate } else if (attempts > 1 && ret == 0) { 1085*7c478bd9Sstevel@tonic-gate (void) printf(": gateway %s (%s)", 1086*7c478bd9Sstevel@tonic-gate gateway, 1087*7c478bd9Sstevel@tonic-gate inet_ntoa(so_gate.sin.sin_addr)); 1088*7c478bd9Sstevel@tonic-gate } else { 1089*7c478bd9Sstevel@tonic-gate (void) printf(": gateway %s", gateway); 1090*7c478bd9Sstevel@tonic-gate } 1091*7c478bd9Sstevel@tonic-gate break; 1092*7c478bd9Sstevel@tonic-gate case AF_INET6: 1093*7c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, 1094*7c478bd9Sstevel@tonic-gate (void *)&so_gate.sin6.sin6_addr, obuf, 1095*7c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN) != NULL) { 1096*7c478bd9Sstevel@tonic-gate if (nflag) { 1097*7c478bd9Sstevel@tonic-gate (void) printf(": gateway %s", 1098*7c478bd9Sstevel@tonic-gate obuf); 1099*7c478bd9Sstevel@tonic-gate } else if (attempts > 1 && ret == 0) { 1100*7c478bd9Sstevel@tonic-gate (void) printf(": gateway %s " 1101*7c478bd9Sstevel@tonic-gate "(%s)", 1102*7c478bd9Sstevel@tonic-gate gateway, obuf); 1103*7c478bd9Sstevel@tonic-gate } 1104*7c478bd9Sstevel@tonic-gate break; 1105*7c478bd9Sstevel@tonic-gate } 1106*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1107*7c478bd9Sstevel@tonic-gate default: 1108*7c478bd9Sstevel@tonic-gate (void) printf(": gateway %s", gateway); 1109*7c478bd9Sstevel@tonic-gate break; 1110*7c478bd9Sstevel@tonic-gate } 1111*7c478bd9Sstevel@tonic-gate } 1112*7c478bd9Sstevel@tonic-gate if (ret == 0) 1113*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 1114*7c478bd9Sstevel@tonic-gate } 1115*7c478bd9Sstevel@tonic-gate if (ret != 0) { 1116*7c478bd9Sstevel@tonic-gate if (*cmd == 'g') { 1117*7c478bd9Sstevel@tonic-gate if (nflag) { 1118*7c478bd9Sstevel@tonic-gate switch (af) { 1119*7c478bd9Sstevel@tonic-gate case AF_INET: 1120*7c478bd9Sstevel@tonic-gate (void) printf(" %s", 1121*7c478bd9Sstevel@tonic-gate inet_ntoa(so_dst.sin.sin_addr)); 1122*7c478bd9Sstevel@tonic-gate break; 1123*7c478bd9Sstevel@tonic-gate case AF_INET6: 1124*7c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, 1125*7c478bd9Sstevel@tonic-gate (void *)&so_dst.sin6.sin6_addr, 1126*7c478bd9Sstevel@tonic-gate obuf, INET6_ADDRSTRLEN) != NULL) { 1127*7c478bd9Sstevel@tonic-gate (void) printf(" %s", obuf); 1128*7c478bd9Sstevel@tonic-gate break; 1129*7c478bd9Sstevel@tonic-gate } 1130*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1131*7c478bd9Sstevel@tonic-gate default: 1132*7c478bd9Sstevel@tonic-gate (void) printf("%s", dest); 1133*7c478bd9Sstevel@tonic-gate break; 1134*7c478bd9Sstevel@tonic-gate } 1135*7c478bd9Sstevel@tonic-gate } else { 1136*7c478bd9Sstevel@tonic-gate (void) printf("%s", dest); 1137*7c478bd9Sstevel@tonic-gate } 1138*7c478bd9Sstevel@tonic-gate } 1139*7c478bd9Sstevel@tonic-gate switch (oerrno) { 1140*7c478bd9Sstevel@tonic-gate case ESRCH: 1141*7c478bd9Sstevel@tonic-gate err = "not in table"; 1142*7c478bd9Sstevel@tonic-gate break; 1143*7c478bd9Sstevel@tonic-gate case EBUSY: 1144*7c478bd9Sstevel@tonic-gate err = "entry in use"; 1145*7c478bd9Sstevel@tonic-gate break; 1146*7c478bd9Sstevel@tonic-gate case ENOBUFS: 1147*7c478bd9Sstevel@tonic-gate err = "routing table overflow"; 1148*7c478bd9Sstevel@tonic-gate break; 1149*7c478bd9Sstevel@tonic-gate case EEXIST: 1150*7c478bd9Sstevel@tonic-gate err = "entry exists"; 1151*7c478bd9Sstevel@tonic-gate break; 1152*7c478bd9Sstevel@tonic-gate case EPERM: 1153*7c478bd9Sstevel@tonic-gate err = "insufficient privileges"; 1154*7c478bd9Sstevel@tonic-gate break; 1155*7c478bd9Sstevel@tonic-gate default: 1156*7c478bd9Sstevel@tonic-gate err = strerror(oerrno); 1157*7c478bd9Sstevel@tonic-gate break; 1158*7c478bd9Sstevel@tonic-gate } 1159*7c478bd9Sstevel@tonic-gate (void) printf(": %s\n", err); 1160*7c478bd9Sstevel@tonic-gate } 1161*7c478bd9Sstevel@tonic-gate /* 1162*7c478bd9Sstevel@tonic-gate * In the case of AF_INET6, one of the getipnodebyX() functions was used 1163*7c478bd9Sstevel@tonic-gate * so free the allocated hostent. 1164*7c478bd9Sstevel@tonic-gate */ 1165*7c478bd9Sstevel@tonic-gate if (af == AF_INET6 && hp != NULL) 1166*7c478bd9Sstevel@tonic-gate freehostent(hp); 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate return (oerrno); 1169*7c478bd9Sstevel@tonic-gate } 1170*7c478bd9Sstevel@tonic-gate 1171*7c478bd9Sstevel@tonic-gate 1172*7c478bd9Sstevel@tonic-gate /* 1173*7c478bd9Sstevel@tonic-gate * Convert a network number to the corresponding IP address. 1174*7c478bd9Sstevel@tonic-gate * If the RTA_NETMASK hasn't been specified yet set it based 1175*7c478bd9Sstevel@tonic-gate * on the class of address. 1176*7c478bd9Sstevel@tonic-gate */ 1177*7c478bd9Sstevel@tonic-gate static void 1178*7c478bd9Sstevel@tonic-gate inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin) 1179*7c478bd9Sstevel@tonic-gate { 1180*7c478bd9Sstevel@tonic-gate in_addr_t addr, mask; 1181*7c478bd9Sstevel@tonic-gate char *cp; 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate if (net == 0) { 1184*7c478bd9Sstevel@tonic-gate mask = addr = 0; 1185*7c478bd9Sstevel@tonic-gate } else if (net < 128) { 1186*7c478bd9Sstevel@tonic-gate addr = net << IN_CLASSA_NSHIFT; 1187*7c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 1188*7c478bd9Sstevel@tonic-gate } else if (net < 65536) { 1189*7c478bd9Sstevel@tonic-gate addr = net << IN_CLASSB_NSHIFT; 1190*7c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 1191*7c478bd9Sstevel@tonic-gate } else if (net < 16777216L) { 1192*7c478bd9Sstevel@tonic-gate addr = net << IN_CLASSC_NSHIFT; 1193*7c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 1194*7c478bd9Sstevel@tonic-gate } else { 1195*7c478bd9Sstevel@tonic-gate addr = net; 1196*7c478bd9Sstevel@tonic-gate if ((addr & IN_CLASSA_HOST) == 0) 1197*7c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 1198*7c478bd9Sstevel@tonic-gate else if ((addr & IN_CLASSB_HOST) == 0) 1199*7c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 1200*7c478bd9Sstevel@tonic-gate else if ((addr & IN_CLASSC_HOST) == 0) 1201*7c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 1202*7c478bd9Sstevel@tonic-gate else { 1203*7c478bd9Sstevel@tonic-gate if (IN_CLASSA(addr)) 1204*7c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 1205*7c478bd9Sstevel@tonic-gate else if (IN_CLASSB(addr)) 1206*7c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 1207*7c478bd9Sstevel@tonic-gate else if (IN_CLASSC(addr)) 1208*7c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 1209*7c478bd9Sstevel@tonic-gate else 1210*7c478bd9Sstevel@tonic-gate mask = IP_HOST_MASK; 1211*7c478bd9Sstevel@tonic-gate mask = inet_makesubnetmask(addr, mask); 1212*7c478bd9Sstevel@tonic-gate } 1213*7c478bd9Sstevel@tonic-gate } 1214*7c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(addr); 1215*7c478bd9Sstevel@tonic-gate 1216*7c478bd9Sstevel@tonic-gate if (!(rtm_addrs & RTA_NETMASK)) { 1217*7c478bd9Sstevel@tonic-gate rtm_addrs |= RTA_NETMASK; 1218*7c478bd9Sstevel@tonic-gate sin = &so_mask.sin; 1219*7c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(mask); 1220*7c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 1221*7c478bd9Sstevel@tonic-gate cp = (char *)(&sin->sin_addr + 1); 1222*7c478bd9Sstevel@tonic-gate while (*--cp == 0 && cp > (char *)sin) 1223*7c478bd9Sstevel@tonic-gate ; 1224*7c478bd9Sstevel@tonic-gate } 1225*7c478bd9Sstevel@tonic-gate } 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate static in_addr_t 1228*7c478bd9Sstevel@tonic-gate inet_makesubnetmask(in_addr_t addr, in_addr_t mask) 1229*7c478bd9Sstevel@tonic-gate { 1230*7c478bd9Sstevel@tonic-gate int n; 1231*7c478bd9Sstevel@tonic-gate struct ifconf ifc; 1232*7c478bd9Sstevel@tonic-gate struct ifreq ifreq; 1233*7c478bd9Sstevel@tonic-gate struct ifreq *ifr; 1234*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 1235*7c478bd9Sstevel@tonic-gate char *buf; 1236*7c478bd9Sstevel@tonic-gate int numifs; 1237*7c478bd9Sstevel@tonic-gate size_t bufsize; 1238*7c478bd9Sstevel@tonic-gate int iosoc; 1239*7c478bd9Sstevel@tonic-gate in_addr_t if_addr, if_mask; 1240*7c478bd9Sstevel@tonic-gate in_addr_t if_subnetmask = 0; 1241*7c478bd9Sstevel@tonic-gate short if_flags; 1242*7c478bd9Sstevel@tonic-gate 1243*7c478bd9Sstevel@tonic-gate if (mask == 0) 1244*7c478bd9Sstevel@tonic-gate return (0); 1245*7c478bd9Sstevel@tonic-gate if ((iosoc = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1246*7c478bd9Sstevel@tonic-gate quit("socket", errno); 1247*7c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFNUM, (char *)&numifs) < 0) 1248*7c478bd9Sstevel@tonic-gate quit("ioctl", errno); 1249*7c478bd9Sstevel@tonic-gate bufsize = numifs * sizeof (struct ifreq); 1250*7c478bd9Sstevel@tonic-gate buf = malloc(bufsize); 1251*7c478bd9Sstevel@tonic-gate if (buf == NULL) 1252*7c478bd9Sstevel@tonic-gate quit("malloc", errno); 1253*7c478bd9Sstevel@tonic-gate (void) memset(&ifc, 0, sizeof (ifc)); 1254*7c478bd9Sstevel@tonic-gate ifc.ifc_len = bufsize; 1255*7c478bd9Sstevel@tonic-gate ifc.ifc_buf = buf; 1256*7c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFCONF, (char *)&ifc) < 0) 1257*7c478bd9Sstevel@tonic-gate quit("ioctl (get interface configuration)", errno); 1258*7c478bd9Sstevel@tonic-gate /* Let's check to see if this is maybe a local subnet route. */ 1259*7c478bd9Sstevel@tonic-gate ifr = ifc.ifc_req; 1260*7c478bd9Sstevel@tonic-gate for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { 1261*7c478bd9Sstevel@tonic-gate ifreq = *ifr; 1262*7c478bd9Sstevel@tonic-gate /* LINTED */ 1263*7c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr->ifr_addr; 1264*7c478bd9Sstevel@tonic-gate if_addr = ntohl(sin->sin_addr.s_addr); 1265*7c478bd9Sstevel@tonic-gate 1266*7c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFFLAGS, (char *)&ifreq) < 0) 1267*7c478bd9Sstevel@tonic-gate quit("ioctl (get interface flags)", errno); 1268*7c478bd9Sstevel@tonic-gate if ((ifreq.ifr_flags & IFF_UP) == 0) 1269*7c478bd9Sstevel@tonic-gate continue; 1270*7c478bd9Sstevel@tonic-gate if_flags = ifreq.ifr_flags; 1271*7c478bd9Sstevel@tonic-gate 1272*7c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFNETMASK, (char *)&ifreq) < 0) 1273*7c478bd9Sstevel@tonic-gate quit("ioctl (get netmask)", errno); 1274*7c478bd9Sstevel@tonic-gate /* LINTED */ 1275*7c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifreq.ifr_addr; 1276*7c478bd9Sstevel@tonic-gate if_mask = ntohl(sin->sin_addr.s_addr); 1277*7c478bd9Sstevel@tonic-gate if ((if_addr & mask) == (addr & mask)) { 1278*7c478bd9Sstevel@tonic-gate /* 1279*7c478bd9Sstevel@tonic-gate * Don't trust pt-pt interfaces if there are 1280*7c478bd9Sstevel@tonic-gate * other interfaces. 1281*7c478bd9Sstevel@tonic-gate */ 1282*7c478bd9Sstevel@tonic-gate if (if_flags & IFF_POINTOPOINT) { 1283*7c478bd9Sstevel@tonic-gate if_subnetmask = if_mask; 1284*7c478bd9Sstevel@tonic-gate continue; 1285*7c478bd9Sstevel@tonic-gate } 1286*7c478bd9Sstevel@tonic-gate /* 1287*7c478bd9Sstevel@tonic-gate * Fine. Just assume the same net mask as the 1288*7c478bd9Sstevel@tonic-gate * directly attached subnet interface is using. 1289*7c478bd9Sstevel@tonic-gate */ 1290*7c478bd9Sstevel@tonic-gate return (if_mask); 1291*7c478bd9Sstevel@tonic-gate } 1292*7c478bd9Sstevel@tonic-gate } 1293*7c478bd9Sstevel@tonic-gate if (if_subnetmask != 0) 1294*7c478bd9Sstevel@tonic-gate return (if_subnetmask); 1295*7c478bd9Sstevel@tonic-gate return (mask); 1296*7c478bd9Sstevel@tonic-gate } 1297*7c478bd9Sstevel@tonic-gate 1298*7c478bd9Sstevel@tonic-gate /* 1299*7c478bd9Sstevel@tonic-gate * Interpret an argument as a network address of some kind, 1300*7c478bd9Sstevel@tonic-gate * returning B_TRUE if a host address, B_FALSE if a network address. 1301*7c478bd9Sstevel@tonic-gate * 1302*7c478bd9Sstevel@tonic-gate * If the address family is one looked up in getaddr() using one of the 1303*7c478bd9Sstevel@tonic-gate * getipnodebyX() functions (currently only AF_INET6), then callers should 1304*7c478bd9Sstevel@tonic-gate * freehostent() the returned "struct hostent" pointer if one was passed in. 1305*7c478bd9Sstevel@tonic-gate */ 1306*7c478bd9Sstevel@tonic-gate static boolean_t 1307*7c478bd9Sstevel@tonic-gate getaddr(int which, char *s, struct hostent **hpp) 1308*7c478bd9Sstevel@tonic-gate { 1309*7c478bd9Sstevel@tonic-gate sup su; 1310*7c478bd9Sstevel@tonic-gate struct hostent *hp; 1311*7c478bd9Sstevel@tonic-gate boolean_t ret; 1312*7c478bd9Sstevel@tonic-gate 1313*7c478bd9Sstevel@tonic-gate if (s == NULL) { 1314*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1315*7c478bd9Sstevel@tonic-gate gettext("route: argument required following keyword\n")); 1316*7c478bd9Sstevel@tonic-gate usage((char *)NULL); 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate if (hpp == NULL) 1319*7c478bd9Sstevel@tonic-gate hpp = &hp; 1320*7c478bd9Sstevel@tonic-gate *hpp = NULL; 1321*7c478bd9Sstevel@tonic-gate rtm_addrs |= which; 1322*7c478bd9Sstevel@tonic-gate switch (which) { 1323*7c478bd9Sstevel@tonic-gate case RTA_DST: 1324*7c478bd9Sstevel@tonic-gate su = &so_dst; 1325*7c478bd9Sstevel@tonic-gate su->sa.sa_family = af; 1326*7c478bd9Sstevel@tonic-gate break; 1327*7c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 1328*7c478bd9Sstevel@tonic-gate su = &so_gate; 1329*7c478bd9Sstevel@tonic-gate su->sa.sa_family = af; 1330*7c478bd9Sstevel@tonic-gate break; 1331*7c478bd9Sstevel@tonic-gate case RTA_NETMASK: 1332*7c478bd9Sstevel@tonic-gate su = &so_mask; 1333*7c478bd9Sstevel@tonic-gate su->sa.sa_family = af; 1334*7c478bd9Sstevel@tonic-gate break; 1335*7c478bd9Sstevel@tonic-gate case RTA_IFP: 1336*7c478bd9Sstevel@tonic-gate so_ifp.sdl.sdl_index = if_nametoindex(s); 1337*7c478bd9Sstevel@tonic-gate if (so_ifp.sdl.sdl_index == 0) { 1338*7c478bd9Sstevel@tonic-gate if (errno == ENXIO) { 1339*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1340*7c478bd9Sstevel@tonic-gate gettext("route: %s: no such interface\n"), 1341*7c478bd9Sstevel@tonic-gate s); 1342*7c478bd9Sstevel@tonic-gate exit(1); 1343*7c478bd9Sstevel@tonic-gate } else { 1344*7c478bd9Sstevel@tonic-gate quit("if_nametoindex", errno); 1345*7c478bd9Sstevel@tonic-gate } 1346*7c478bd9Sstevel@tonic-gate } 1347*7c478bd9Sstevel@tonic-gate so_ifp.sdl.sdl_family = AF_LINK; 1348*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1349*7c478bd9Sstevel@tonic-gate /* 1350*7c478bd9Sstevel@tonic-gate * RTA_SRC has overloaded meaning. It can represent the 1351*7c478bd9Sstevel@tonic-gate * src address of incoming or outgoing packets. 1352*7c478bd9Sstevel@tonic-gate */ 1353*7c478bd9Sstevel@tonic-gate case RTA_IFA: 1354*7c478bd9Sstevel@tonic-gate su = &so_ifa; 1355*7c478bd9Sstevel@tonic-gate su->sa.sa_family = af; 1356*7c478bd9Sstevel@tonic-gate break; 1357*7c478bd9Sstevel@tonic-gate case RTA_SRC: 1358*7c478bd9Sstevel@tonic-gate su = &so_src; 1359*7c478bd9Sstevel@tonic-gate su->sa.sa_family = af; 1360*7c478bd9Sstevel@tonic-gate break; 1361*7c478bd9Sstevel@tonic-gate default: 1362*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1363*7c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 1364*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1365*7c478bd9Sstevel@tonic-gate } 1366*7c478bd9Sstevel@tonic-gate if (strcmp(s, "default") == 0) { 1367*7c478bd9Sstevel@tonic-gate if (which == RTA_DST) { 1368*7c478bd9Sstevel@tonic-gate forcenet = B_TRUE; 1369*7c478bd9Sstevel@tonic-gate (void) getaddr(RTA_NETMASK, s, NULL); 1370*7c478bd9Sstevel@tonic-gate } 1371*7c478bd9Sstevel@tonic-gate if (which == RTA_SRC) { 1372*7c478bd9Sstevel@tonic-gate return (B_TRUE); 1373*7c478bd9Sstevel@tonic-gate } 1374*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1375*7c478bd9Sstevel@tonic-gate } 1376*7c478bd9Sstevel@tonic-gate switch (af) { 1377*7c478bd9Sstevel@tonic-gate case AF_LINK: 1378*7c478bd9Sstevel@tonic-gate link_addr(s, &su->sdl); 1379*7c478bd9Sstevel@tonic-gate return (B_TRUE); 1380*7c478bd9Sstevel@tonic-gate case PF_ROUTE: 1381*7c478bd9Sstevel@tonic-gate sockaddr(s, &su->sa); 1382*7c478bd9Sstevel@tonic-gate return (B_TRUE); 1383*7c478bd9Sstevel@tonic-gate case AF_INET6: 1384*7c478bd9Sstevel@tonic-gate switch (which) { 1385*7c478bd9Sstevel@tonic-gate case RTA_DST: 1386*7c478bd9Sstevel@tonic-gate if (s[0] == '/') { 1387*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1388*7c478bd9Sstevel@tonic-gate gettext("route: %s: unexpected '/'\n"), s); 1389*7c478bd9Sstevel@tonic-gate exit(1); 1390*7c478bd9Sstevel@tonic-gate } 1391*7c478bd9Sstevel@tonic-gate ret = in6_getaddr(s, &su->sin6, &masklen, hpp); 1392*7c478bd9Sstevel@tonic-gate switch (masklen) { 1393*7c478bd9Sstevel@tonic-gate case NO_PREFIX: 1394*7c478bd9Sstevel@tonic-gate /* Nothing there - ok */ 1395*7c478bd9Sstevel@tonic-gate return (ret); 1396*7c478bd9Sstevel@tonic-gate case BAD_ADDR: 1397*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1398*7c478bd9Sstevel@tonic-gate gettext("route: bad prefix length in %s\n"), 1399*7c478bd9Sstevel@tonic-gate s); 1400*7c478bd9Sstevel@tonic-gate exit(1); 1401*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1402*7c478bd9Sstevel@tonic-gate default: 1403*7c478bd9Sstevel@tonic-gate (void) memset(&so_mask.sin6.sin6_addr, 0, 1404*7c478bd9Sstevel@tonic-gate sizeof (so_mask.sin6.sin6_addr)); 1405*7c478bd9Sstevel@tonic-gate if (!in_prefixlentomask(masklen, IPV6_ABITS, 1406*7c478bd9Sstevel@tonic-gate (uchar_t *)&so_mask.sin6.sin6_addr)) { 1407*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1408*7c478bd9Sstevel@tonic-gate gettext("route: bad prefix length: " 1409*7c478bd9Sstevel@tonic-gate "%d\n"), masklen); 1410*7c478bd9Sstevel@tonic-gate exit(1); 1411*7c478bd9Sstevel@tonic-gate } 1412*7c478bd9Sstevel@tonic-gate break; 1413*7c478bd9Sstevel@tonic-gate } 1414*7c478bd9Sstevel@tonic-gate so_mask.sin6.sin6_family = af; 1415*7c478bd9Sstevel@tonic-gate rtm_addrs |= RTA_NETMASK; 1416*7c478bd9Sstevel@tonic-gate return (ret); 1417*7c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 1418*7c478bd9Sstevel@tonic-gate case RTA_IFA: 1419*7c478bd9Sstevel@tonic-gate case RTA_SRC: 1420*7c478bd9Sstevel@tonic-gate ret = in6_getaddr(s, &su->sin6, NULL, hpp); 1421*7c478bd9Sstevel@tonic-gate return (ret); 1422*7c478bd9Sstevel@tonic-gate case RTA_NETMASK: 1423*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1424*7c478bd9Sstevel@tonic-gate gettext("route: -netmask not supported for IPv6: " 1425*7c478bd9Sstevel@tonic-gate "use <prefix>/<prefix-length> instead")); 1426*7c478bd9Sstevel@tonic-gate exit(1); 1427*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1428*7c478bd9Sstevel@tonic-gate default: 1429*7c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 1430*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1431*7c478bd9Sstevel@tonic-gate } 1432*7c478bd9Sstevel@tonic-gate case AF_INET: 1433*7c478bd9Sstevel@tonic-gate switch (which) { 1434*7c478bd9Sstevel@tonic-gate case RTA_DST: 1435*7c478bd9Sstevel@tonic-gate if (s[0] == '/') { 1436*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1437*7c478bd9Sstevel@tonic-gate gettext("route: %s: unexpected '/'\n"), s); 1438*7c478bd9Sstevel@tonic-gate exit(1); 1439*7c478bd9Sstevel@tonic-gate } 1440*7c478bd9Sstevel@tonic-gate ret = in_getaddr(s, &su->sin, &masklen, which, hpp); 1441*7c478bd9Sstevel@tonic-gate switch (masklen) { 1442*7c478bd9Sstevel@tonic-gate case NO_PREFIX: 1443*7c478bd9Sstevel@tonic-gate /* Nothing there - ok */ 1444*7c478bd9Sstevel@tonic-gate return (ret); 1445*7c478bd9Sstevel@tonic-gate case BAD_ADDR: 1446*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1447*7c478bd9Sstevel@tonic-gate gettext("route: bad prefix length in %s\n"), 1448*7c478bd9Sstevel@tonic-gate s); 1449*7c478bd9Sstevel@tonic-gate exit(1); 1450*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1451*7c478bd9Sstevel@tonic-gate default: 1452*7c478bd9Sstevel@tonic-gate (void) memset(&so_mask.sin.sin_addr, 0, 1453*7c478bd9Sstevel@tonic-gate sizeof (so_mask.sin.sin_addr)); 1454*7c478bd9Sstevel@tonic-gate if (!in_prefixlentomask(masklen, IP_ABITS, 1455*7c478bd9Sstevel@tonic-gate (uchar_t *)&so_mask.sin.sin_addr)) { 1456*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1457*7c478bd9Sstevel@tonic-gate gettext("route: bad prefix length: " 1458*7c478bd9Sstevel@tonic-gate "%d\n"), masklen); 1459*7c478bd9Sstevel@tonic-gate exit(1); 1460*7c478bd9Sstevel@tonic-gate } 1461*7c478bd9Sstevel@tonic-gate break; 1462*7c478bd9Sstevel@tonic-gate } 1463*7c478bd9Sstevel@tonic-gate so_mask.sin.sin_family = af; 1464*7c478bd9Sstevel@tonic-gate rtm_addrs |= RTA_NETMASK; 1465*7c478bd9Sstevel@tonic-gate return (ret); 1466*7c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 1467*7c478bd9Sstevel@tonic-gate case RTA_IFA: 1468*7c478bd9Sstevel@tonic-gate case RTA_NETMASK: 1469*7c478bd9Sstevel@tonic-gate case RTA_SRC: 1470*7c478bd9Sstevel@tonic-gate ret = in_getaddr(s, &su->sin, NULL, which, hpp); 1471*7c478bd9Sstevel@tonic-gate return (ret); 1472*7c478bd9Sstevel@tonic-gate default: 1473*7c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 1474*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1475*7c478bd9Sstevel@tonic-gate } 1476*7c478bd9Sstevel@tonic-gate default: 1477*7c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 1478*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1479*7c478bd9Sstevel@tonic-gate } 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate } 1482*7c478bd9Sstevel@tonic-gate 1483*7c478bd9Sstevel@tonic-gate /* 1484*7c478bd9Sstevel@tonic-gate * Interpret an argument as an IPv4 network address of some kind, 1485*7c478bd9Sstevel@tonic-gate * returning B_TRUE if a host address, B_FALSE if a network address. 1486*7c478bd9Sstevel@tonic-gate * Note that this *always* tries host interpretation before network 1487*7c478bd9Sstevel@tonic-gate * interpretation. 1488*7c478bd9Sstevel@tonic-gate * 1489*7c478bd9Sstevel@tonic-gate * If the plenp argument is non-NULL, allow <addr>/<n> syntax and 1490*7c478bd9Sstevel@tonic-gate * pass out <n> in *plenp. 1491*7c478bd9Sstevel@tonic-gate * If <n> doesn't parse return BAD_ADDR as *plenp. 1492*7c478bd9Sstevel@tonic-gate * If no /<n> is present return NO_PREFIX as *plenp. 1493*7c478bd9Sstevel@tonic-gate */ 1494*7c478bd9Sstevel@tonic-gate static boolean_t 1495*7c478bd9Sstevel@tonic-gate in_getaddr(char *s, struct sockaddr_in *sin, int *plenp, int which, 1496*7c478bd9Sstevel@tonic-gate struct hostent **hpp) 1497*7c478bd9Sstevel@tonic-gate { 1498*7c478bd9Sstevel@tonic-gate struct hostent *hp; 1499*7c478bd9Sstevel@tonic-gate struct netent *np; 1500*7c478bd9Sstevel@tonic-gate in_addr_t val; 1501*7c478bd9Sstevel@tonic-gate char str[BUFSIZ]; 1502*7c478bd9Sstevel@tonic-gate 1503*7c478bd9Sstevel@tonic-gate (void) strncpy(str, s, sizeof (str)); 1504*7c478bd9Sstevel@tonic-gate 1505*7c478bd9Sstevel@tonic-gate /* 1506*7c478bd9Sstevel@tonic-gate * Look for '/'<n> is plenp 1507*7c478bd9Sstevel@tonic-gate */ 1508*7c478bd9Sstevel@tonic-gate if (plenp != NULL) { 1509*7c478bd9Sstevel@tonic-gate char *cp; 1510*7c478bd9Sstevel@tonic-gate 1511*7c478bd9Sstevel@tonic-gate *plenp = in_getprefixlen(str, IP_ABITS); 1512*7c478bd9Sstevel@tonic-gate if (*plenp == BAD_ADDR) 1513*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1514*7c478bd9Sstevel@tonic-gate cp = strchr(str, '/'); 1515*7c478bd9Sstevel@tonic-gate if (cp != NULL) 1516*7c478bd9Sstevel@tonic-gate *cp = '\0'; 1517*7c478bd9Sstevel@tonic-gate } else if (strchr(str, '/') != NULL) { 1518*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"), 1519*7c478bd9Sstevel@tonic-gate str); 1520*7c478bd9Sstevel@tonic-gate exit(1); 1521*7c478bd9Sstevel@tonic-gate } 1522*7c478bd9Sstevel@tonic-gate 1523*7c478bd9Sstevel@tonic-gate (void) memset(sin, 0, sizeof (*sin)); 1524*7c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 1525*7c478bd9Sstevel@tonic-gate 1526*7c478bd9Sstevel@tonic-gate /* 1527*7c478bd9Sstevel@tonic-gate * Note: only the route destination can be a network, so we treat 1528*7c478bd9Sstevel@tonic-gate * all other addresses as though "-net" was not specified. 1529*7c478bd9Sstevel@tonic-gate */ 1530*7c478bd9Sstevel@tonic-gate if ((((val = inet_addr(str)) != (in_addr_t)-1) || 1531*7c478bd9Sstevel@tonic-gate strcmp(str, "255.255.255.255") == 0) && 1532*7c478bd9Sstevel@tonic-gate (which != RTA_DST || !forcenet)) { 1533*7c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = val; 1534*7c478bd9Sstevel@tonic-gate if (inet_lnaof(sin->sin_addr) != INADDR_ANY || 1535*7c478bd9Sstevel@tonic-gate forcehost) 1536*7c478bd9Sstevel@tonic-gate return (B_TRUE); 1537*7c478bd9Sstevel@tonic-gate val = ntohl(val); 1538*7c478bd9Sstevel@tonic-gate if (which == RTA_DST) 1539*7c478bd9Sstevel@tonic-gate inet_makenetandmask(val, sin); 1540*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1541*7c478bd9Sstevel@tonic-gate } 1542*7c478bd9Sstevel@tonic-gate if (!forcehost && (val = inet_network(str)) != (in_addr_t)-1) { 1543*7c478bd9Sstevel@tonic-gate if (which == RTA_DST) 1544*7c478bd9Sstevel@tonic-gate inet_makenetandmask(val, sin); 1545*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1546*7c478bd9Sstevel@tonic-gate } 1547*7c478bd9Sstevel@tonic-gate if ((which != RTA_DST || !forcenet) && 1548*7c478bd9Sstevel@tonic-gate (hp = gethostbyname(str)) != NULL) { 1549*7c478bd9Sstevel@tonic-gate *hpp = hp; 1550*7c478bd9Sstevel@tonic-gate (void) memmove(&sin->sin_addr, hp->h_addr, 1551*7c478bd9Sstevel@tonic-gate hp->h_length); 1552*7c478bd9Sstevel@tonic-gate return (B_TRUE); 1553*7c478bd9Sstevel@tonic-gate } 1554*7c478bd9Sstevel@tonic-gate if (!forcehost && (np = getnetbyname(str)) != NULL && 1555*7c478bd9Sstevel@tonic-gate (val = np->n_net) != 0) { 1556*7c478bd9Sstevel@tonic-gate if (which == RTA_DST) 1557*7c478bd9Sstevel@tonic-gate inet_makenetandmask(val, sin); 1558*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1559*7c478bd9Sstevel@tonic-gate } 1560*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: bad value\n"), s); 1561*7c478bd9Sstevel@tonic-gate exit(1); 1562*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1563*7c478bd9Sstevel@tonic-gate } 1564*7c478bd9Sstevel@tonic-gate 1565*7c478bd9Sstevel@tonic-gate /* 1566*7c478bd9Sstevel@tonic-gate * Interpret an argument as an IPv6 network address of some kind, 1567*7c478bd9Sstevel@tonic-gate * returning B_TRUE if a host address, B_FALSE if a network address. 1568*7c478bd9Sstevel@tonic-gate * 1569*7c478bd9Sstevel@tonic-gate * If the last argument is non-NULL allow a <addr>/<n> syntax and 1570*7c478bd9Sstevel@tonic-gate * pass out <n> in *plenp. 1571*7c478bd9Sstevel@tonic-gate * If <n> doesn't parse return BAD_ADDR as *plenp. 1572*7c478bd9Sstevel@tonic-gate * If no /<n> is present return NO_PREFIX as *plenp. 1573*7c478bd9Sstevel@tonic-gate */ 1574*7c478bd9Sstevel@tonic-gate static boolean_t 1575*7c478bd9Sstevel@tonic-gate in6_getaddr(char *s, struct sockaddr_in6 *sin6, int *plenp, 1576*7c478bd9Sstevel@tonic-gate struct hostent **hpp) 1577*7c478bd9Sstevel@tonic-gate { 1578*7c478bd9Sstevel@tonic-gate struct hostent *hp; 1579*7c478bd9Sstevel@tonic-gate char str[BUFSIZ]; 1580*7c478bd9Sstevel@tonic-gate int error_num; 1581*7c478bd9Sstevel@tonic-gate 1582*7c478bd9Sstevel@tonic-gate (void) strncpy(str, s, sizeof (str)); 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate /* 1585*7c478bd9Sstevel@tonic-gate * Look for '/'<n> is plenp 1586*7c478bd9Sstevel@tonic-gate */ 1587*7c478bd9Sstevel@tonic-gate if (plenp != NULL) { 1588*7c478bd9Sstevel@tonic-gate char *cp; 1589*7c478bd9Sstevel@tonic-gate 1590*7c478bd9Sstevel@tonic-gate *plenp = in_getprefixlen(str, IPV6_ABITS); 1591*7c478bd9Sstevel@tonic-gate if (*plenp == BAD_ADDR) 1592*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1593*7c478bd9Sstevel@tonic-gate cp = strchr(str, '/'); 1594*7c478bd9Sstevel@tonic-gate if (cp != NULL) 1595*7c478bd9Sstevel@tonic-gate *cp = '\0'; 1596*7c478bd9Sstevel@tonic-gate } else if (strchr(str, '/') != NULL) { 1597*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"), 1598*7c478bd9Sstevel@tonic-gate str); 1599*7c478bd9Sstevel@tonic-gate exit(1); 1600*7c478bd9Sstevel@tonic-gate } 1601*7c478bd9Sstevel@tonic-gate 1602*7c478bd9Sstevel@tonic-gate (void) memset(sin6, 0, sizeof (struct sockaddr_in6)); 1603*7c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 1604*7c478bd9Sstevel@tonic-gate 1605*7c478bd9Sstevel@tonic-gate hp = getipnodebyname(str, AF_INET6, 0, &error_num); 1606*7c478bd9Sstevel@tonic-gate if (hp != NULL) { 1607*7c478bd9Sstevel@tonic-gate *hpp = hp; 1608*7c478bd9Sstevel@tonic-gate (void) memmove(&sin6->sin6_addr, hp->h_addr, hp->h_length); 1609*7c478bd9Sstevel@tonic-gate return (B_TRUE); 1610*7c478bd9Sstevel@tonic-gate } 1611*7c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 1612*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: %s: bad address (try " 1613*7c478bd9Sstevel@tonic-gate "again later)\n"), s); 1614*7c478bd9Sstevel@tonic-gate } else { 1615*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: %s: bad address\n"), s); 1616*7c478bd9Sstevel@tonic-gate } 1617*7c478bd9Sstevel@tonic-gate exit(1); 1618*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1619*7c478bd9Sstevel@tonic-gate } 1620*7c478bd9Sstevel@tonic-gate 1621*7c478bd9Sstevel@tonic-gate /* 1622*7c478bd9Sstevel@tonic-gate * If "slash" is zero this parses the whole string as 1623*7c478bd9Sstevel@tonic-gate * an integer. With "slash" non zero it parses the tail part as an integer. 1624*7c478bd9Sstevel@tonic-gate * 1625*7c478bd9Sstevel@tonic-gate * If it is not a valid integer this returns BAD_ADDR. 1626*7c478bd9Sstevel@tonic-gate * If there is /<n> present this returns NO_PREFIX. 1627*7c478bd9Sstevel@tonic-gate */ 1628*7c478bd9Sstevel@tonic-gate int 1629*7c478bd9Sstevel@tonic-gate in_getprefixlen(char *addr, int max_plen) 1630*7c478bd9Sstevel@tonic-gate { 1631*7c478bd9Sstevel@tonic-gate int prefixlen; 1632*7c478bd9Sstevel@tonic-gate char *str, *end; 1633*7c478bd9Sstevel@tonic-gate 1634*7c478bd9Sstevel@tonic-gate str = strchr(addr, '/'); 1635*7c478bd9Sstevel@tonic-gate if (str == NULL) 1636*7c478bd9Sstevel@tonic-gate return (NO_PREFIX); 1637*7c478bd9Sstevel@tonic-gate str++; 1638*7c478bd9Sstevel@tonic-gate 1639*7c478bd9Sstevel@tonic-gate prefixlen = strtol(str, &end, 10); 1640*7c478bd9Sstevel@tonic-gate if (prefixlen < 0) 1641*7c478bd9Sstevel@tonic-gate return (BAD_ADDR); 1642*7c478bd9Sstevel@tonic-gate if (str == end) 1643*7c478bd9Sstevel@tonic-gate return (BAD_ADDR); 1644*7c478bd9Sstevel@tonic-gate if (max_plen != 0 && max_plen < prefixlen) 1645*7c478bd9Sstevel@tonic-gate return (BAD_ADDR); 1646*7c478bd9Sstevel@tonic-gate else 1647*7c478bd9Sstevel@tonic-gate return (prefixlen); 1648*7c478bd9Sstevel@tonic-gate } 1649*7c478bd9Sstevel@tonic-gate 1650*7c478bd9Sstevel@tonic-gate /* 1651*7c478bd9Sstevel@tonic-gate * Convert a prefix length to a mask. 1652*7c478bd9Sstevel@tonic-gate * Returns B_TRUE if ok. B_FALSE otherwise. 1653*7c478bd9Sstevel@tonic-gate * Assumes the mask array is zeroed by the caller. 1654*7c478bd9Sstevel@tonic-gate */ 1655*7c478bd9Sstevel@tonic-gate boolean_t 1656*7c478bd9Sstevel@tonic-gate in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 1657*7c478bd9Sstevel@tonic-gate { 1658*7c478bd9Sstevel@tonic-gate if (prefixlen < 0 || prefixlen > maxlen) 1659*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1660*7c478bd9Sstevel@tonic-gate 1661*7c478bd9Sstevel@tonic-gate while (prefixlen > 0) { 1662*7c478bd9Sstevel@tonic-gate if (prefixlen >= 8) { 1663*7c478bd9Sstevel@tonic-gate *mask++ = 0xFF; 1664*7c478bd9Sstevel@tonic-gate prefixlen -= 8; 1665*7c478bd9Sstevel@tonic-gate continue; 1666*7c478bd9Sstevel@tonic-gate } 1667*7c478bd9Sstevel@tonic-gate *mask |= 1 << (8 - prefixlen); 1668*7c478bd9Sstevel@tonic-gate prefixlen--; 1669*7c478bd9Sstevel@tonic-gate } 1670*7c478bd9Sstevel@tonic-gate return (B_TRUE); 1671*7c478bd9Sstevel@tonic-gate } 1672*7c478bd9Sstevel@tonic-gate 1673*7c478bd9Sstevel@tonic-gate void 1674*7c478bd9Sstevel@tonic-gate rtmonitor(int argc, char *argv[]) 1675*7c478bd9Sstevel@tonic-gate { 1676*7c478bd9Sstevel@tonic-gate int n; 1677*7c478bd9Sstevel@tonic-gate intmax_t msg[2048 / sizeof (intmax_t)]; 1678*7c478bd9Sstevel@tonic-gate 1679*7c478bd9Sstevel@tonic-gate if (tflag) 1680*7c478bd9Sstevel@tonic-gate exit(0); 1681*7c478bd9Sstevel@tonic-gate verbose = B_TRUE; 1682*7c478bd9Sstevel@tonic-gate if (argc > 1) { 1683*7c478bd9Sstevel@tonic-gate argv++; 1684*7c478bd9Sstevel@tonic-gate if (argc == 2 && **argv == '-') { 1685*7c478bd9Sstevel@tonic-gate switch (keyword(*argv + 1)) { 1686*7c478bd9Sstevel@tonic-gate case K_INET: 1687*7c478bd9Sstevel@tonic-gate af = AF_INET; 1688*7c478bd9Sstevel@tonic-gate break; 1689*7c478bd9Sstevel@tonic-gate case K_LINK: 1690*7c478bd9Sstevel@tonic-gate af = AF_LINK; 1691*7c478bd9Sstevel@tonic-gate break; 1692*7c478bd9Sstevel@tonic-gate case K_INET6: 1693*7c478bd9Sstevel@tonic-gate af = AF_INET6; 1694*7c478bd9Sstevel@tonic-gate break; 1695*7c478bd9Sstevel@tonic-gate default: 1696*7c478bd9Sstevel@tonic-gate usage(*argv); 1697*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1698*7c478bd9Sstevel@tonic-gate } 1699*7c478bd9Sstevel@tonic-gate } else { 1700*7c478bd9Sstevel@tonic-gate usage(*argv); 1701*7c478bd9Sstevel@tonic-gate } 1702*7c478bd9Sstevel@tonic-gate (void) close(s); 1703*7c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, af); 1704*7c478bd9Sstevel@tonic-gate if (s < 0) 1705*7c478bd9Sstevel@tonic-gate quit("socket", errno); 1706*7c478bd9Sstevel@tonic-gate } 1707*7c478bd9Sstevel@tonic-gate for (;;) { 1708*7c478bd9Sstevel@tonic-gate n = read(s, msg, sizeof (msg)); 1709*7c478bd9Sstevel@tonic-gate if (n <= 0) 1710*7c478bd9Sstevel@tonic-gate quit("read", errno); 1711*7c478bd9Sstevel@tonic-gate (void) printf("got message of size %d\n", n); 1712*7c478bd9Sstevel@tonic-gate print_rtmsg((struct rt_msghdr *)msg, n); 1713*7c478bd9Sstevel@tonic-gate } 1714*7c478bd9Sstevel@tonic-gate } 1715*7c478bd9Sstevel@tonic-gate 1716*7c478bd9Sstevel@tonic-gate int 1717*7c478bd9Sstevel@tonic-gate rtmsg(int cmd, int flags) 1718*7c478bd9Sstevel@tonic-gate { 1719*7c478bd9Sstevel@tonic-gate static int seq; 1720*7c478bd9Sstevel@tonic-gate int rlen; 1721*7c478bd9Sstevel@tonic-gate char *cp = m_rtmsg.m_space; 1722*7c478bd9Sstevel@tonic-gate int l; 1723*7c478bd9Sstevel@tonic-gate 1724*7c478bd9Sstevel@tonic-gate errno = 0; 1725*7c478bd9Sstevel@tonic-gate (void) memset(&m_rtmsg, 0, sizeof (m_rtmsg)); 1726*7c478bd9Sstevel@tonic-gate if (cmd == 'a') { 1727*7c478bd9Sstevel@tonic-gate cmd = RTM_ADD; 1728*7c478bd9Sstevel@tonic-gate } else if (cmd == 'c') { 1729*7c478bd9Sstevel@tonic-gate cmd = RTM_CHANGE; 1730*7c478bd9Sstevel@tonic-gate } else if (cmd == 'g') { 1731*7c478bd9Sstevel@tonic-gate cmd = RTM_GET; 1732*7c478bd9Sstevel@tonic-gate if (so_ifp.sa.sa_family == 0) { 1733*7c478bd9Sstevel@tonic-gate so_ifp.sa.sa_family = AF_LINK; 1734*7c478bd9Sstevel@tonic-gate rtm_addrs |= RTA_IFP; 1735*7c478bd9Sstevel@tonic-gate } 1736*7c478bd9Sstevel@tonic-gate } else { 1737*7c478bd9Sstevel@tonic-gate cmd = RTM_DELETE; 1738*7c478bd9Sstevel@tonic-gate } 1739*7c478bd9Sstevel@tonic-gate #define rtm m_rtmsg.m_rtm 1740*7c478bd9Sstevel@tonic-gate rtm.rtm_type = cmd; 1741*7c478bd9Sstevel@tonic-gate rtm.rtm_flags = flags; 1742*7c478bd9Sstevel@tonic-gate rtm.rtm_version = RTM_VERSION; 1743*7c478bd9Sstevel@tonic-gate rtm.rtm_seq = ++seq; 1744*7c478bd9Sstevel@tonic-gate rtm.rtm_addrs = rtm_addrs; 1745*7c478bd9Sstevel@tonic-gate rtm.rtm_rmx = rt_metrics; 1746*7c478bd9Sstevel@tonic-gate rtm.rtm_inits = rtm_inits; 1747*7c478bd9Sstevel@tonic-gate 1748*7c478bd9Sstevel@tonic-gate #define NEXTADDR(w, u) \ 1749*7c478bd9Sstevel@tonic-gate if (rtm_addrs & (w)) { \ 1750*7c478bd9Sstevel@tonic-gate l = ROUNDUP_LONG(salen(&u.sa)); \ 1751*7c478bd9Sstevel@tonic-gate (void) memmove(cp, &(u), l); \ 1752*7c478bd9Sstevel@tonic-gate cp += l; \ 1753*7c478bd9Sstevel@tonic-gate if (verbose) \ 1754*7c478bd9Sstevel@tonic-gate sodump(&(u), #u); \ 1755*7c478bd9Sstevel@tonic-gate } 1756*7c478bd9Sstevel@tonic-gate NEXTADDR(RTA_DST, so_dst); 1757*7c478bd9Sstevel@tonic-gate NEXTADDR(RTA_GATEWAY, so_gate); 1758*7c478bd9Sstevel@tonic-gate NEXTADDR(RTA_NETMASK, so_mask); 1759*7c478bd9Sstevel@tonic-gate NEXTADDR(RTA_IFP, so_ifp); 1760*7c478bd9Sstevel@tonic-gate NEXTADDR(RTA_IFA, so_ifa); 1761*7c478bd9Sstevel@tonic-gate /* 1762*7c478bd9Sstevel@tonic-gate * RTA_SRC has overloaded meaning. It can represent the 1763*7c478bd9Sstevel@tonic-gate * src address of incoming or outgoing packets. 1764*7c478bd9Sstevel@tonic-gate */ 1765*7c478bd9Sstevel@tonic-gate NEXTADDR(RTA_SRC, so_src); 1766*7c478bd9Sstevel@tonic-gate #undef NEXTADDR 1767*7c478bd9Sstevel@tonic-gate rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 1768*7c478bd9Sstevel@tonic-gate if (verbose) 1769*7c478bd9Sstevel@tonic-gate print_rtmsg(&rtm, l); 1770*7c478bd9Sstevel@tonic-gate if (debugonly) 1771*7c478bd9Sstevel@tonic-gate return (0); 1772*7c478bd9Sstevel@tonic-gate if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 1773*7c478bd9Sstevel@tonic-gate switch (errno) { 1774*7c478bd9Sstevel@tonic-gate case ESRCH: 1775*7c478bd9Sstevel@tonic-gate case EBUSY: 1776*7c478bd9Sstevel@tonic-gate case ENOBUFS: 1777*7c478bd9Sstevel@tonic-gate case EEXIST: 1778*7c478bd9Sstevel@tonic-gate case ENETUNREACH: 1779*7c478bd9Sstevel@tonic-gate case EHOSTUNREACH: 1780*7c478bd9Sstevel@tonic-gate case EPERM: 1781*7c478bd9Sstevel@tonic-gate break; 1782*7c478bd9Sstevel@tonic-gate default: 1783*7c478bd9Sstevel@tonic-gate perror(gettext("writing to routing socket")); 1784*7c478bd9Sstevel@tonic-gate break; 1785*7c478bd9Sstevel@tonic-gate } 1786*7c478bd9Sstevel@tonic-gate return (-1); 1787*7c478bd9Sstevel@tonic-gate } else if (rlen < (int)rtm.rtm_msglen) { 1788*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1789*7c478bd9Sstevel@tonic-gate gettext("route: write to routing socket got only %d for " 1790*7c478bd9Sstevel@tonic-gate "len\n"), rlen); 1791*7c478bd9Sstevel@tonic-gate return (-1); 1792*7c478bd9Sstevel@tonic-gate } 1793*7c478bd9Sstevel@tonic-gate if (cmd == RTM_GET) { 1794*7c478bd9Sstevel@tonic-gate do { 1795*7c478bd9Sstevel@tonic-gate l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg)); 1796*7c478bd9Sstevel@tonic-gate } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 1797*7c478bd9Sstevel@tonic-gate if (l < 0) { 1798*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1799*7c478bd9Sstevel@tonic-gate gettext("route: read from routing socket: %s\n"), 1800*7c478bd9Sstevel@tonic-gate strerror(errno)); 1801*7c478bd9Sstevel@tonic-gate } else { 1802*7c478bd9Sstevel@tonic-gate print_getmsg(&rtm, l); 1803*7c478bd9Sstevel@tonic-gate } 1804*7c478bd9Sstevel@tonic-gate } 1805*7c478bd9Sstevel@tonic-gate #undef rtm 1806*7c478bd9Sstevel@tonic-gate return (0); 1807*7c478bd9Sstevel@tonic-gate } 1808*7c478bd9Sstevel@tonic-gate 1809*7c478bd9Sstevel@tonic-gate static char *msgtypes[] = { 1810*7c478bd9Sstevel@tonic-gate "", 1811*7c478bd9Sstevel@tonic-gate "RTM_ADD: Add Route", 1812*7c478bd9Sstevel@tonic-gate "RTM_DELETE: Delete Route", 1813*7c478bd9Sstevel@tonic-gate "RTM_CHANGE: Change Metrics or flags", 1814*7c478bd9Sstevel@tonic-gate "RTM_GET: Report Metrics", 1815*7c478bd9Sstevel@tonic-gate "RTM_LOSING: Kernel Suspects Partitioning", 1816*7c478bd9Sstevel@tonic-gate "RTM_REDIRECT: Told to use different route", 1817*7c478bd9Sstevel@tonic-gate "RTM_MISS: Lookup failed on this address", 1818*7c478bd9Sstevel@tonic-gate "RTM_LOCK: fix specified metrics", 1819*7c478bd9Sstevel@tonic-gate "RTM_OLDADD: caused by SIOCADDRT", 1820*7c478bd9Sstevel@tonic-gate "RTM_OLDDEL: caused by SIOCDELRT", 1821*7c478bd9Sstevel@tonic-gate "RTM_RESOLVE: Route created by cloning", 1822*7c478bd9Sstevel@tonic-gate "RTM_NEWADDR: address being added to iface", 1823*7c478bd9Sstevel@tonic-gate "RTM_DELADDR: address being removed from iface", 1824*7c478bd9Sstevel@tonic-gate "RTM_IFINFO: iface status change", 1825*7c478bd9Sstevel@tonic-gate 0, 1826*7c478bd9Sstevel@tonic-gate }; 1827*7c478bd9Sstevel@tonic-gate 1828*7c478bd9Sstevel@tonic-gate #define NMSGTYPES (sizeof (msgtypes) / sizeof (msgtypes[0])) 1829*7c478bd9Sstevel@tonic-gate 1830*7c478bd9Sstevel@tonic-gate static char metricnames[] = 1831*7c478bd9Sstevel@tonic-gate "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount" 1832*7c478bd9Sstevel@tonic-gate "\1mtu"; 1833*7c478bd9Sstevel@tonic-gate static char routeflags[] = 1834*7c478bd9Sstevel@tonic-gate "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT" 1835*7c478bd9Sstevel@tonic-gate "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 1836*7c478bd9Sstevel@tonic-gate "\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC"; 1837*7c478bd9Sstevel@tonic-gate static char ifnetflags[] = 1838*7c478bd9Sstevel@tonic-gate "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP" 1839*7c478bd9Sstevel@tonic-gate "\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST" 1840*7c478bd9Sstevel@tonic-gate "\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE" 1841*7c478bd9Sstevel@tonic-gate "\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF" 1842*7c478bd9Sstevel@tonic-gate "\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6" 1843*7c478bd9Sstevel@tonic-gate "\033MIP\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE" 1844*7c478bd9Sstevel@tonic-gate "\041XRESOLV\042COS\043PREFERRED\044TEMPORARY"; 1845*7c478bd9Sstevel@tonic-gate static char addrnames[] = 1846*7c478bd9Sstevel@tonic-gate "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC"; 1847*7c478bd9Sstevel@tonic-gate 1848*7c478bd9Sstevel@tonic-gate void 1849*7c478bd9Sstevel@tonic-gate print_rtmsg(struct rt_msghdr *rtm, int msglen) 1850*7c478bd9Sstevel@tonic-gate { 1851*7c478bd9Sstevel@tonic-gate struct if_msghdr *ifm; 1852*7c478bd9Sstevel@tonic-gate struct ifa_msghdr *ifam; 1853*7c478bd9Sstevel@tonic-gate 1854*7c478bd9Sstevel@tonic-gate if (!verbose) 1855*7c478bd9Sstevel@tonic-gate return; 1856*7c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 1857*7c478bd9Sstevel@tonic-gate (void) printf("routing message version %d not understood\n", 1858*7c478bd9Sstevel@tonic-gate rtm->rtm_version); 1859*7c478bd9Sstevel@tonic-gate return; 1860*7c478bd9Sstevel@tonic-gate } 1861*7c478bd9Sstevel@tonic-gate if (rtm->rtm_msglen > (ushort_t)msglen) { 1862*7c478bd9Sstevel@tonic-gate (void) printf("message length mismatch, in packet %d, " 1863*7c478bd9Sstevel@tonic-gate "returned %d\n", 1864*7c478bd9Sstevel@tonic-gate rtm->rtm_msglen, msglen); 1865*7c478bd9Sstevel@tonic-gate } 1866*7c478bd9Sstevel@tonic-gate /* 1867*7c478bd9Sstevel@tonic-gate * Since rtm->rtm_type is unsigned, we'll just check the case of zero 1868*7c478bd9Sstevel@tonic-gate * and the upper-bound of (NMSGTYPES - 1). 1869*7c478bd9Sstevel@tonic-gate */ 1870*7c478bd9Sstevel@tonic-gate if (rtm->rtm_type == 0 || rtm->rtm_type >= (NMSGTYPES - 1)) { 1871*7c478bd9Sstevel@tonic-gate (void) printf("routing message type %d not understood\n", 1872*7c478bd9Sstevel@tonic-gate rtm->rtm_type); 1873*7c478bd9Sstevel@tonic-gate return; 1874*7c478bd9Sstevel@tonic-gate } 1875*7c478bd9Sstevel@tonic-gate (void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen); 1876*7c478bd9Sstevel@tonic-gate switch (rtm->rtm_type) { 1877*7c478bd9Sstevel@tonic-gate case RTM_IFINFO: 1878*7c478bd9Sstevel@tonic-gate ifm = (struct if_msghdr *)rtm; 1879*7c478bd9Sstevel@tonic-gate (void) printf("if# %d, flags:", ifm->ifm_index); 1880*7c478bd9Sstevel@tonic-gate bprintf(stdout, ifm->ifm_flags, ifnetflags); 1881*7c478bd9Sstevel@tonic-gate pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 1882*7c478bd9Sstevel@tonic-gate break; 1883*7c478bd9Sstevel@tonic-gate case RTM_NEWADDR: 1884*7c478bd9Sstevel@tonic-gate case RTM_DELADDR: 1885*7c478bd9Sstevel@tonic-gate ifam = (struct ifa_msghdr *)rtm; 1886*7c478bd9Sstevel@tonic-gate (void) printf("metric %d, flags:", ifam->ifam_metric); 1887*7c478bd9Sstevel@tonic-gate bprintf(stdout, ifam->ifam_flags, routeflags); 1888*7c478bd9Sstevel@tonic-gate pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); 1889*7c478bd9Sstevel@tonic-gate break; 1890*7c478bd9Sstevel@tonic-gate default: 1891*7c478bd9Sstevel@tonic-gate (void) printf("pid: %ld, seq %d, errno %d, flags:", 1892*7c478bd9Sstevel@tonic-gate rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 1893*7c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_flags, routeflags); 1894*7c478bd9Sstevel@tonic-gate pmsg_common(rtm); 1895*7c478bd9Sstevel@tonic-gate } 1896*7c478bd9Sstevel@tonic-gate } 1897*7c478bd9Sstevel@tonic-gate 1898*7c478bd9Sstevel@tonic-gate void 1899*7c478bd9Sstevel@tonic-gate print_getmsg(struct rt_msghdr *rtm, int msglen) 1900*7c478bd9Sstevel@tonic-gate { 1901*7c478bd9Sstevel@tonic-gate struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL; 1902*7c478bd9Sstevel@tonic-gate struct sockaddr_dl *ifp = NULL; 1903*7c478bd9Sstevel@tonic-gate struct sockaddr *sa; 1904*7c478bd9Sstevel@tonic-gate char *cp; 1905*7c478bd9Sstevel@tonic-gate int i; 1906*7c478bd9Sstevel@tonic-gate 1907*7c478bd9Sstevel@tonic-gate (void) printf(" route to: %s\n", routename(&so_dst.sa)); 1908*7c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 1909*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1910*7c478bd9Sstevel@tonic-gate gettext("routing message version %d not understood\n"), 1911*7c478bd9Sstevel@tonic-gate rtm->rtm_version); 1912*7c478bd9Sstevel@tonic-gate return; 1913*7c478bd9Sstevel@tonic-gate } 1914*7c478bd9Sstevel@tonic-gate if (rtm->rtm_msglen > (ushort_t)msglen) { 1915*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1916*7c478bd9Sstevel@tonic-gate gettext("message length mismatch, in packet %d, " 1917*7c478bd9Sstevel@tonic-gate "returned %d\n"), rtm->rtm_msglen, msglen); 1918*7c478bd9Sstevel@tonic-gate } 1919*7c478bd9Sstevel@tonic-gate if (rtm->rtm_errno) { 1920*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "RTM_GET: %s (errno %d)\n", 1921*7c478bd9Sstevel@tonic-gate strerror(rtm->rtm_errno), rtm->rtm_errno); 1922*7c478bd9Sstevel@tonic-gate return; 1923*7c478bd9Sstevel@tonic-gate } 1924*7c478bd9Sstevel@tonic-gate cp = ((char *)(rtm + 1)); 1925*7c478bd9Sstevel@tonic-gate if (rtm->rtm_addrs != 0) { 1926*7c478bd9Sstevel@tonic-gate for (i = 1; i != 0; i <<= 1) { 1927*7c478bd9Sstevel@tonic-gate if (i & rtm->rtm_addrs) { 1928*7c478bd9Sstevel@tonic-gate /* LINTED */ 1929*7c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)cp; 1930*7c478bd9Sstevel@tonic-gate switch (i) { 1931*7c478bd9Sstevel@tonic-gate case RTA_DST: 1932*7c478bd9Sstevel@tonic-gate dst = sa; 1933*7c478bd9Sstevel@tonic-gate break; 1934*7c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 1935*7c478bd9Sstevel@tonic-gate gate = sa; 1936*7c478bd9Sstevel@tonic-gate break; 1937*7c478bd9Sstevel@tonic-gate case RTA_NETMASK: 1938*7c478bd9Sstevel@tonic-gate mask = sa; 1939*7c478bd9Sstevel@tonic-gate break; 1940*7c478bd9Sstevel@tonic-gate case RTA_IFP: 1941*7c478bd9Sstevel@tonic-gate if (sa->sa_family == AF_LINK && 1942*7c478bd9Sstevel@tonic-gate ((struct sockaddr_dl *)sa)-> 1943*7c478bd9Sstevel@tonic-gate sdl_nlen != 0) 1944*7c478bd9Sstevel@tonic-gate ifp = (struct sockaddr_dl *)sa; 1945*7c478bd9Sstevel@tonic-gate break; 1946*7c478bd9Sstevel@tonic-gate case RTA_SRC: 1947*7c478bd9Sstevel@tonic-gate src = sa; 1948*7c478bd9Sstevel@tonic-gate break; 1949*7c478bd9Sstevel@tonic-gate } 1950*7c478bd9Sstevel@tonic-gate ADVANCE(cp, sa); 1951*7c478bd9Sstevel@tonic-gate } 1952*7c478bd9Sstevel@tonic-gate } 1953*7c478bd9Sstevel@tonic-gate } 1954*7c478bd9Sstevel@tonic-gate if (dst != NULL && mask != NULL) 1955*7c478bd9Sstevel@tonic-gate mask->sa_family = dst->sa_family; /* XXX */ 1956*7c478bd9Sstevel@tonic-gate if (dst != NULL) 1957*7c478bd9Sstevel@tonic-gate (void) printf("destination: %s\n", routename(dst)); 1958*7c478bd9Sstevel@tonic-gate if (mask != NULL) { 1959*7c478bd9Sstevel@tonic-gate boolean_t savenflag = nflag; 1960*7c478bd9Sstevel@tonic-gate 1961*7c478bd9Sstevel@tonic-gate nflag = B_TRUE; 1962*7c478bd9Sstevel@tonic-gate (void) printf(" mask: %s\n", routename(mask)); 1963*7c478bd9Sstevel@tonic-gate nflag = savenflag; 1964*7c478bd9Sstevel@tonic-gate } 1965*7c478bd9Sstevel@tonic-gate if (gate != NULL && rtm->rtm_flags & RTF_GATEWAY) 1966*7c478bd9Sstevel@tonic-gate (void) printf(" gateway: %s\n", routename(gate)); 1967*7c478bd9Sstevel@tonic-gate if (src != NULL && rtm->rtm_flags & RTF_SETSRC) 1968*7c478bd9Sstevel@tonic-gate (void) printf(" setsrc: %s\n", routename(src)); 1969*7c478bd9Sstevel@tonic-gate if (ifp != NULL) { 1970*7c478bd9Sstevel@tonic-gate if (verbose) { 1971*7c478bd9Sstevel@tonic-gate int i; 1972*7c478bd9Sstevel@tonic-gate 1973*7c478bd9Sstevel@tonic-gate (void) printf(" interface: %.*s index %d address ", 1974*7c478bd9Sstevel@tonic-gate ifp->sdl_nlen, ifp->sdl_data, ifp->sdl_index); 1975*7c478bd9Sstevel@tonic-gate for (i = ifp->sdl_nlen; 1976*7c478bd9Sstevel@tonic-gate i < ifp->sdl_nlen + ifp->sdl_alen; 1977*7c478bd9Sstevel@tonic-gate i++) { 1978*7c478bd9Sstevel@tonic-gate (void) printf("%02x ", 1979*7c478bd9Sstevel@tonic-gate ifp->sdl_data[i] & 0xFF); 1980*7c478bd9Sstevel@tonic-gate } 1981*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 1982*7c478bd9Sstevel@tonic-gate } else { 1983*7c478bd9Sstevel@tonic-gate (void) printf(" interface: %.*s\n", 1984*7c478bd9Sstevel@tonic-gate ifp->sdl_nlen, ifp->sdl_data); 1985*7c478bd9Sstevel@tonic-gate } 1986*7c478bd9Sstevel@tonic-gate } 1987*7c478bd9Sstevel@tonic-gate (void) printf(" flags: "); 1988*7c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_flags, routeflags); 1989*7c478bd9Sstevel@tonic-gate 1990*7c478bd9Sstevel@tonic-gate #define lock(f) ((rtm->rtm_rmx.rmx_locks & RTV_ ## f) ? 'L' : ' ') 1991*7c478bd9Sstevel@tonic-gate #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 1992*7c478bd9Sstevel@tonic-gate 1993*7c478bd9Sstevel@tonic-gate (void) printf("\n%s\n", " recvpipe sendpipe ssthresh rtt,ms " 1994*7c478bd9Sstevel@tonic-gate "rttvar,ms hopcount mtu expire"); 1995*7c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 1996*7c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 1997*7c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 1998*7c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 1999*7c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 2000*7c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 2001*7c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 2002*7c478bd9Sstevel@tonic-gate if (rtm->rtm_rmx.rmx_expire) 2003*7c478bd9Sstevel@tonic-gate rtm->rtm_rmx.rmx_expire -= time(0); 2004*7c478bd9Sstevel@tonic-gate (void) printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 2005*7c478bd9Sstevel@tonic-gate #undef lock 2006*7c478bd9Sstevel@tonic-gate #undef msec 2007*7c478bd9Sstevel@tonic-gate #define RTA_IGN \ 2008*7c478bd9Sstevel@tonic-gate (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC) 2009*7c478bd9Sstevel@tonic-gate if (verbose) { 2010*7c478bd9Sstevel@tonic-gate pmsg_common(rtm); 2011*7c478bd9Sstevel@tonic-gate } else if (rtm->rtm_addrs &~ RTA_IGN) { 2012*7c478bd9Sstevel@tonic-gate (void) printf("sockaddrs: "); 2013*7c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_addrs, addrnames); 2014*7c478bd9Sstevel@tonic-gate (void) putchar('\n'); 2015*7c478bd9Sstevel@tonic-gate } 2016*7c478bd9Sstevel@tonic-gate #undef RTA_IGN 2017*7c478bd9Sstevel@tonic-gate } 2018*7c478bd9Sstevel@tonic-gate 2019*7c478bd9Sstevel@tonic-gate void 2020*7c478bd9Sstevel@tonic-gate pmsg_common(struct rt_msghdr *rtm) 2021*7c478bd9Sstevel@tonic-gate { 2022*7c478bd9Sstevel@tonic-gate (void) printf("\nlocks: "); 2023*7c478bd9Sstevel@tonic-gate bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames); 2024*7c478bd9Sstevel@tonic-gate (void) printf(" inits: "); 2025*7c478bd9Sstevel@tonic-gate bprintf(stdout, (int)rtm->rtm_inits, metricnames); 2026*7c478bd9Sstevel@tonic-gate pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs); 2027*7c478bd9Sstevel@tonic-gate } 2028*7c478bd9Sstevel@tonic-gate 2029*7c478bd9Sstevel@tonic-gate void 2030*7c478bd9Sstevel@tonic-gate pmsg_addrs(char *cp, int addrs) 2031*7c478bd9Sstevel@tonic-gate { 2032*7c478bd9Sstevel@tonic-gate struct sockaddr *sa; 2033*7c478bd9Sstevel@tonic-gate int i; 2034*7c478bd9Sstevel@tonic-gate 2035*7c478bd9Sstevel@tonic-gate if (addrs == 0) 2036*7c478bd9Sstevel@tonic-gate return; 2037*7c478bd9Sstevel@tonic-gate (void) printf("\nsockaddrs: "); 2038*7c478bd9Sstevel@tonic-gate bprintf(stdout, addrs, addrnames); 2039*7c478bd9Sstevel@tonic-gate (void) putchar('\n'); 2040*7c478bd9Sstevel@tonic-gate for (i = 1; i != 0; i <<= 1) { 2041*7c478bd9Sstevel@tonic-gate if (i & addrs) { 2042*7c478bd9Sstevel@tonic-gate /* LINTED */ 2043*7c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)cp; 2044*7c478bd9Sstevel@tonic-gate (void) printf(" %s", routename(sa)); 2045*7c478bd9Sstevel@tonic-gate ADVANCE(cp, sa); 2046*7c478bd9Sstevel@tonic-gate } 2047*7c478bd9Sstevel@tonic-gate } 2048*7c478bd9Sstevel@tonic-gate (void) putchar('\n'); 2049*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 2050*7c478bd9Sstevel@tonic-gate } 2051*7c478bd9Sstevel@tonic-gate 2052*7c478bd9Sstevel@tonic-gate void 2053*7c478bd9Sstevel@tonic-gate bprintf(FILE *fp, int b, char *s) 2054*7c478bd9Sstevel@tonic-gate { 2055*7c478bd9Sstevel@tonic-gate int i; 2056*7c478bd9Sstevel@tonic-gate boolean_t gotsome = B_FALSE; 2057*7c478bd9Sstevel@tonic-gate 2058*7c478bd9Sstevel@tonic-gate if (b == 0) 2059*7c478bd9Sstevel@tonic-gate return; 2060*7c478bd9Sstevel@tonic-gate while ((i = *s++) != 0) { 2061*7c478bd9Sstevel@tonic-gate if (b & (1 << (i - 1))) { 2062*7c478bd9Sstevel@tonic-gate if (!gotsome) 2063*7c478bd9Sstevel@tonic-gate i = '<'; 2064*7c478bd9Sstevel@tonic-gate else 2065*7c478bd9Sstevel@tonic-gate i = ','; 2066*7c478bd9Sstevel@tonic-gate (void) putc(i, fp); 2067*7c478bd9Sstevel@tonic-gate gotsome = B_TRUE; 2068*7c478bd9Sstevel@tonic-gate for (; (i = *s) > ' '; s++) 2069*7c478bd9Sstevel@tonic-gate (void) putc(i, fp); 2070*7c478bd9Sstevel@tonic-gate } else { 2071*7c478bd9Sstevel@tonic-gate while (*s > ' ') 2072*7c478bd9Sstevel@tonic-gate s++; 2073*7c478bd9Sstevel@tonic-gate } 2074*7c478bd9Sstevel@tonic-gate } 2075*7c478bd9Sstevel@tonic-gate if (gotsome) 2076*7c478bd9Sstevel@tonic-gate (void) putc('>', fp); 2077*7c478bd9Sstevel@tonic-gate } 2078*7c478bd9Sstevel@tonic-gate 2079*7c478bd9Sstevel@tonic-gate int 2080*7c478bd9Sstevel@tonic-gate keyword(char *cp) 2081*7c478bd9Sstevel@tonic-gate { 2082*7c478bd9Sstevel@tonic-gate struct keytab *kt = keywords; 2083*7c478bd9Sstevel@tonic-gate 2084*7c478bd9Sstevel@tonic-gate while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 2085*7c478bd9Sstevel@tonic-gate kt++; 2086*7c478bd9Sstevel@tonic-gate return (kt->kt_i); 2087*7c478bd9Sstevel@tonic-gate } 2088*7c478bd9Sstevel@tonic-gate 2089*7c478bd9Sstevel@tonic-gate void 2090*7c478bd9Sstevel@tonic-gate sodump(sup su, char *which) 2091*7c478bd9Sstevel@tonic-gate { 2092*7c478bd9Sstevel@tonic-gate static char obuf[INET6_ADDRSTRLEN]; 2093*7c478bd9Sstevel@tonic-gate 2094*7c478bd9Sstevel@tonic-gate switch (su->sa.sa_family) { 2095*7c478bd9Sstevel@tonic-gate case AF_LINK: 2096*7c478bd9Sstevel@tonic-gate (void) printf("%s: link %s; ", 2097*7c478bd9Sstevel@tonic-gate which, link_ntoa(&su->sdl)); 2098*7c478bd9Sstevel@tonic-gate break; 2099*7c478bd9Sstevel@tonic-gate case AF_INET: 2100*7c478bd9Sstevel@tonic-gate (void) printf("%s: inet %s; ", 2101*7c478bd9Sstevel@tonic-gate which, inet_ntoa(su->sin.sin_addr)); 2102*7c478bd9Sstevel@tonic-gate break; 2103*7c478bd9Sstevel@tonic-gate case AF_INET6: 2104*7c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, (void *)&su->sin6.sin6_addr, obuf, 2105*7c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN) != NULL) { 2106*7c478bd9Sstevel@tonic-gate (void) printf("%s: inet6 %s; ", which, obuf); 2107*7c478bd9Sstevel@tonic-gate break; 2108*7c478bd9Sstevel@tonic-gate } 2109*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 2110*7c478bd9Sstevel@tonic-gate default: 2111*7c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 2112*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2113*7c478bd9Sstevel@tonic-gate } 2114*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 2115*7c478bd9Sstevel@tonic-gate } 2116*7c478bd9Sstevel@tonic-gate 2117*7c478bd9Sstevel@tonic-gate /* States */ 2118*7c478bd9Sstevel@tonic-gate #define VIRGIN 0 2119*7c478bd9Sstevel@tonic-gate #define GOTONE 1 2120*7c478bd9Sstevel@tonic-gate #define GOTTWO 2 2121*7c478bd9Sstevel@tonic-gate #define RESET 3 2122*7c478bd9Sstevel@tonic-gate /* Inputs */ 2123*7c478bd9Sstevel@tonic-gate #define DIGIT (4*0) 2124*7c478bd9Sstevel@tonic-gate #define END (4*1) 2125*7c478bd9Sstevel@tonic-gate #define DELIM (4*2) 2126*7c478bd9Sstevel@tonic-gate #define LETTER (4*3) 2127*7c478bd9Sstevel@tonic-gate 2128*7c478bd9Sstevel@tonic-gate void 2129*7c478bd9Sstevel@tonic-gate sockaddr(char *addr, struct sockaddr *sa) 2130*7c478bd9Sstevel@tonic-gate { 2131*7c478bd9Sstevel@tonic-gate char *cp = (char *)sa; 2132*7c478bd9Sstevel@tonic-gate int size = salen(sa); 2133*7c478bd9Sstevel@tonic-gate char *cplim = cp + size; 2134*7c478bd9Sstevel@tonic-gate int byte = 0, state = VIRGIN, new; 2135*7c478bd9Sstevel@tonic-gate 2136*7c478bd9Sstevel@tonic-gate (void) memset(cp, 0, size); 2137*7c478bd9Sstevel@tonic-gate cp++; 2138*7c478bd9Sstevel@tonic-gate do { 2139*7c478bd9Sstevel@tonic-gate if ((*addr >= '0') && (*addr <= '9')) { 2140*7c478bd9Sstevel@tonic-gate new = *addr - '0'; 2141*7c478bd9Sstevel@tonic-gate } else if ((*addr >= 'a') && (*addr <= 'f')) { 2142*7c478bd9Sstevel@tonic-gate new = *addr - 'a' + 10; 2143*7c478bd9Sstevel@tonic-gate } else if ((*addr >= 'A') && (*addr <= 'F')) { 2144*7c478bd9Sstevel@tonic-gate new = *addr - 'A' + 10; 2145*7c478bd9Sstevel@tonic-gate } else if (*addr == 0) { 2146*7c478bd9Sstevel@tonic-gate state |= END; 2147*7c478bd9Sstevel@tonic-gate } else { 2148*7c478bd9Sstevel@tonic-gate state |= DELIM; 2149*7c478bd9Sstevel@tonic-gate } 2150*7c478bd9Sstevel@tonic-gate addr++; 2151*7c478bd9Sstevel@tonic-gate switch (state /* | INPUT */) { 2152*7c478bd9Sstevel@tonic-gate case GOTTWO | DIGIT: 2153*7c478bd9Sstevel@tonic-gate *cp++ = byte; 2154*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 2155*7c478bd9Sstevel@tonic-gate case VIRGIN | DIGIT: 2156*7c478bd9Sstevel@tonic-gate state = GOTONE; byte = new; continue; 2157*7c478bd9Sstevel@tonic-gate case GOTONE | DIGIT: 2158*7c478bd9Sstevel@tonic-gate state = GOTTWO; byte = new + (byte << 4); continue; 2159*7c478bd9Sstevel@tonic-gate default: /* | DELIM */ 2160*7c478bd9Sstevel@tonic-gate state = VIRGIN; *cp++ = byte; byte = 0; continue; 2161*7c478bd9Sstevel@tonic-gate case GOTONE | END: 2162*7c478bd9Sstevel@tonic-gate case GOTTWO | END: 2163*7c478bd9Sstevel@tonic-gate *cp++ = byte; 2164*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 2165*7c478bd9Sstevel@tonic-gate case VIRGIN | END: 2166*7c478bd9Sstevel@tonic-gate break; 2167*7c478bd9Sstevel@tonic-gate } 2168*7c478bd9Sstevel@tonic-gate break; 2169*7c478bd9Sstevel@tonic-gate } while (cp < cplim); 2170*7c478bd9Sstevel@tonic-gate } 2171*7c478bd9Sstevel@tonic-gate 2172*7c478bd9Sstevel@tonic-gate int 2173*7c478bd9Sstevel@tonic-gate salen(struct sockaddr *sa) 2174*7c478bd9Sstevel@tonic-gate { 2175*7c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 2176*7c478bd9Sstevel@tonic-gate case AF_INET: 2177*7c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_in)); 2178*7c478bd9Sstevel@tonic-gate case AF_LINK: 2179*7c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_dl)); 2180*7c478bd9Sstevel@tonic-gate case AF_INET6: 2181*7c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_in6)); 2182*7c478bd9Sstevel@tonic-gate default: 2183*7c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr)); 2184*7c478bd9Sstevel@tonic-gate } 2185*7c478bd9Sstevel@tonic-gate } 2186*7c478bd9Sstevel@tonic-gate 2187*7c478bd9Sstevel@tonic-gate void 2188*7c478bd9Sstevel@tonic-gate link_addr(const char *addr, struct sockaddr_dl *sdl) 2189*7c478bd9Sstevel@tonic-gate { 2190*7c478bd9Sstevel@tonic-gate char *cp = sdl->sdl_data; 2191*7c478bd9Sstevel@tonic-gate char *cplim = sizeof (struct sockaddr_dl) + (char *)sdl; 2192*7c478bd9Sstevel@tonic-gate int byte = 0, state = VIRGIN, new; 2193*7c478bd9Sstevel@tonic-gate 2194*7c478bd9Sstevel@tonic-gate (void) memset(sdl, 0, sizeof (struct sockaddr_dl)); 2195*7c478bd9Sstevel@tonic-gate sdl->sdl_family = AF_LINK; 2196*7c478bd9Sstevel@tonic-gate do { 2197*7c478bd9Sstevel@tonic-gate state &= ~LETTER; 2198*7c478bd9Sstevel@tonic-gate if ((*addr >= '0') && (*addr <= '9')) { 2199*7c478bd9Sstevel@tonic-gate new = *addr - '0'; 2200*7c478bd9Sstevel@tonic-gate } else if ((*addr >= 'a') && (*addr <= 'f')) { 2201*7c478bd9Sstevel@tonic-gate new = *addr - 'a' + 10; 2202*7c478bd9Sstevel@tonic-gate } else if ((*addr >= 'A') && (*addr <= 'F')) { 2203*7c478bd9Sstevel@tonic-gate new = *addr - 'A' + 10; 2204*7c478bd9Sstevel@tonic-gate } else if (*addr == 0) { 2205*7c478bd9Sstevel@tonic-gate state |= END; 2206*7c478bd9Sstevel@tonic-gate } else if (state == VIRGIN && 2207*7c478bd9Sstevel@tonic-gate (((*addr >= 'A') && (*addr <= 'Z')) || 2208*7c478bd9Sstevel@tonic-gate ((*addr >= 'a') && (*addr <= 'z')))) { 2209*7c478bd9Sstevel@tonic-gate state |= LETTER; 2210*7c478bd9Sstevel@tonic-gate } else { 2211*7c478bd9Sstevel@tonic-gate state |= DELIM; 2212*7c478bd9Sstevel@tonic-gate } 2213*7c478bd9Sstevel@tonic-gate addr++; 2214*7c478bd9Sstevel@tonic-gate switch (state /* | INPUT */) { 2215*7c478bd9Sstevel@tonic-gate case VIRGIN | DIGIT: 2216*7c478bd9Sstevel@tonic-gate case VIRGIN | LETTER: 2217*7c478bd9Sstevel@tonic-gate *cp++ = addr[-1]; 2218*7c478bd9Sstevel@tonic-gate continue; 2219*7c478bd9Sstevel@tonic-gate case VIRGIN | DELIM: 2220*7c478bd9Sstevel@tonic-gate state = RESET; 2221*7c478bd9Sstevel@tonic-gate sdl->sdl_nlen = cp - sdl->sdl_data; 2222*7c478bd9Sstevel@tonic-gate continue; 2223*7c478bd9Sstevel@tonic-gate case GOTTWO | DIGIT: 2224*7c478bd9Sstevel@tonic-gate *cp++ = byte; 2225*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 2226*7c478bd9Sstevel@tonic-gate case RESET | DIGIT: 2227*7c478bd9Sstevel@tonic-gate state = GOTONE; 2228*7c478bd9Sstevel@tonic-gate byte = new; 2229*7c478bd9Sstevel@tonic-gate continue; 2230*7c478bd9Sstevel@tonic-gate case GOTONE | DIGIT: 2231*7c478bd9Sstevel@tonic-gate state = GOTTWO; 2232*7c478bd9Sstevel@tonic-gate byte = new + (byte << 4); 2233*7c478bd9Sstevel@tonic-gate continue; 2234*7c478bd9Sstevel@tonic-gate default: /* | DELIM */ 2235*7c478bd9Sstevel@tonic-gate state = RESET; 2236*7c478bd9Sstevel@tonic-gate *cp++ = byte; 2237*7c478bd9Sstevel@tonic-gate byte = 0; 2238*7c478bd9Sstevel@tonic-gate continue; 2239*7c478bd9Sstevel@tonic-gate case GOTONE | END: 2240*7c478bd9Sstevel@tonic-gate case GOTTWO | END: 2241*7c478bd9Sstevel@tonic-gate *cp++ = byte; 2242*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 2243*7c478bd9Sstevel@tonic-gate case RESET | END: 2244*7c478bd9Sstevel@tonic-gate break; 2245*7c478bd9Sstevel@tonic-gate } 2246*7c478bd9Sstevel@tonic-gate break; 2247*7c478bd9Sstevel@tonic-gate } while (cp < cplim); 2248*7c478bd9Sstevel@tonic-gate sdl->sdl_alen = cp - LLADDR(sdl); 2249*7c478bd9Sstevel@tonic-gate } 2250*7c478bd9Sstevel@tonic-gate 2251*7c478bd9Sstevel@tonic-gate static char hexlist[] = "0123456789abcdef"; 2252*7c478bd9Sstevel@tonic-gate 2253*7c478bd9Sstevel@tonic-gate char * 2254*7c478bd9Sstevel@tonic-gate link_ntoa(const struct sockaddr_dl *sdl) 2255*7c478bd9Sstevel@tonic-gate { 2256*7c478bd9Sstevel@tonic-gate static char obuf[64]; 2257*7c478bd9Sstevel@tonic-gate char *out = obuf; 2258*7c478bd9Sstevel@tonic-gate int i; 2259*7c478bd9Sstevel@tonic-gate uchar_t *in = (uchar_t *)LLADDR(sdl); 2260*7c478bd9Sstevel@tonic-gate uchar_t *inlim = in + sdl->sdl_alen; 2261*7c478bd9Sstevel@tonic-gate boolean_t firsttime = B_TRUE; 2262*7c478bd9Sstevel@tonic-gate 2263*7c478bd9Sstevel@tonic-gate if (sdl->sdl_nlen) { 2264*7c478bd9Sstevel@tonic-gate (void) memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen); 2265*7c478bd9Sstevel@tonic-gate out += sdl->sdl_nlen; 2266*7c478bd9Sstevel@tonic-gate if (sdl->sdl_alen) 2267*7c478bd9Sstevel@tonic-gate *out++ = ':'; 2268*7c478bd9Sstevel@tonic-gate } 2269*7c478bd9Sstevel@tonic-gate while (in < inlim) { 2270*7c478bd9Sstevel@tonic-gate if (firsttime) 2271*7c478bd9Sstevel@tonic-gate firsttime = B_FALSE; 2272*7c478bd9Sstevel@tonic-gate else 2273*7c478bd9Sstevel@tonic-gate *out++ = '.'; 2274*7c478bd9Sstevel@tonic-gate i = *in++; 2275*7c478bd9Sstevel@tonic-gate if (i > 0xf) { 2276*7c478bd9Sstevel@tonic-gate out[1] = hexlist[i & 0xf]; 2277*7c478bd9Sstevel@tonic-gate i >>= 4; 2278*7c478bd9Sstevel@tonic-gate out[0] = hexlist[i]; 2279*7c478bd9Sstevel@tonic-gate out += 2; 2280*7c478bd9Sstevel@tonic-gate } else { 2281*7c478bd9Sstevel@tonic-gate *out++ = hexlist[i]; 2282*7c478bd9Sstevel@tonic-gate } 2283*7c478bd9Sstevel@tonic-gate } 2284*7c478bd9Sstevel@tonic-gate *out = 0; 2285*7c478bd9Sstevel@tonic-gate return (obuf); 2286*7c478bd9Sstevel@tonic-gate } 2287*7c478bd9Sstevel@tonic-gate 2288*7c478bd9Sstevel@tonic-gate static mib_item_t * 2289*7c478bd9Sstevel@tonic-gate mibget(int sd) 2290*7c478bd9Sstevel@tonic-gate { 2291*7c478bd9Sstevel@tonic-gate intmax_t buf[512 / sizeof (intmax_t)]; 2292*7c478bd9Sstevel@tonic-gate int flags; 2293*7c478bd9Sstevel@tonic-gate int i, j, getcode; 2294*7c478bd9Sstevel@tonic-gate struct strbuf ctlbuf, databuf; 2295*7c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; 2296*7c478bd9Sstevel@tonic-gate struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; 2297*7c478bd9Sstevel@tonic-gate struct T_error_ack *tea = (struct T_error_ack *)buf; 2298*7c478bd9Sstevel@tonic-gate struct opthdr *req; 2299*7c478bd9Sstevel@tonic-gate mib_item_t *first_item = NULL; 2300*7c478bd9Sstevel@tonic-gate mib_item_t *last_item = NULL; 2301*7c478bd9Sstevel@tonic-gate mib_item_t *temp; 2302*7c478bd9Sstevel@tonic-gate 2303*7c478bd9Sstevel@tonic-gate tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 2304*7c478bd9Sstevel@tonic-gate tor->OPT_offset = sizeof (struct T_optmgmt_req); 2305*7c478bd9Sstevel@tonic-gate tor->OPT_length = sizeof (struct opthdr); 2306*7c478bd9Sstevel@tonic-gate tor->MGMT_flags = T_CURRENT; 2307*7c478bd9Sstevel@tonic-gate req = (struct opthdr *)&tor[1]; 2308*7c478bd9Sstevel@tonic-gate req->level = MIB2_IP; /* any MIB2_xxx value ok here */ 2309*7c478bd9Sstevel@tonic-gate req->name = 0; 2310*7c478bd9Sstevel@tonic-gate req->len = 0; 2311*7c478bd9Sstevel@tonic-gate 2312*7c478bd9Sstevel@tonic-gate ctlbuf.buf = (char *)buf; 2313*7c478bd9Sstevel@tonic-gate ctlbuf.len = tor->OPT_length + tor->OPT_offset; 2314*7c478bd9Sstevel@tonic-gate flags = 0; 2315*7c478bd9Sstevel@tonic-gate if (putmsg(sd, &ctlbuf, NULL, flags) < 0) { 2316*7c478bd9Sstevel@tonic-gate perror("mibget: putmsg (ctl)"); 2317*7c478bd9Sstevel@tonic-gate return (NULL); 2318*7c478bd9Sstevel@tonic-gate } 2319*7c478bd9Sstevel@tonic-gate /* 2320*7c478bd9Sstevel@tonic-gate * each reply consists of a ctl part for one fixed structure 2321*7c478bd9Sstevel@tonic-gate * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK, 2322*7c478bd9Sstevel@tonic-gate * containing an opthdr structure. level/name identify the entry, 2323*7c478bd9Sstevel@tonic-gate * len is the size of the data part of the message. 2324*7c478bd9Sstevel@tonic-gate */ 2325*7c478bd9Sstevel@tonic-gate req = (struct opthdr *)&toa[1]; 2326*7c478bd9Sstevel@tonic-gate ctlbuf.maxlen = sizeof (buf); 2327*7c478bd9Sstevel@tonic-gate for (j = 1; ; j++) { 2328*7c478bd9Sstevel@tonic-gate flags = 0; 2329*7c478bd9Sstevel@tonic-gate getcode = getmsg(sd, &ctlbuf, NULL, &flags); 2330*7c478bd9Sstevel@tonic-gate if (getcode < 0) { 2331*7c478bd9Sstevel@tonic-gate perror("mibget: getmsg (ctl)"); 2332*7c478bd9Sstevel@tonic-gate if (verbose) { 2333*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2334*7c478bd9Sstevel@tonic-gate "# level name len\n"); 2335*7c478bd9Sstevel@tonic-gate i = 0; 2336*7c478bd9Sstevel@tonic-gate for (last_item = first_item; last_item != NULL; 2337*7c478bd9Sstevel@tonic-gate last_item = last_item->next_item) { 2338*7c478bd9Sstevel@tonic-gate (void) printf("%d %4ld %5ld %ld\n", 2339*7c478bd9Sstevel@tonic-gate ++i, last_item->group, 2340*7c478bd9Sstevel@tonic-gate last_item->mib_id, 2341*7c478bd9Sstevel@tonic-gate last_item->length); 2342*7c478bd9Sstevel@tonic-gate } 2343*7c478bd9Sstevel@tonic-gate } 2344*7c478bd9Sstevel@tonic-gate break; 2345*7c478bd9Sstevel@tonic-gate } 2346*7c478bd9Sstevel@tonic-gate if (getcode == 0 && 2347*7c478bd9Sstevel@tonic-gate ctlbuf.len >= sizeof (struct T_optmgmt_ack) && 2348*7c478bd9Sstevel@tonic-gate toa->PRIM_type == T_OPTMGMT_ACK && 2349*7c478bd9Sstevel@tonic-gate toa->MGMT_flags == T_SUCCESS && 2350*7c478bd9Sstevel@tonic-gate req->len == 0) { 2351*7c478bd9Sstevel@tonic-gate if (verbose) { 2352*7c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg() %d returned EOD " 2353*7c478bd9Sstevel@tonic-gate "(level %lu, name %lu)\n", j, req->level, 2354*7c478bd9Sstevel@tonic-gate req->name); 2355*7c478bd9Sstevel@tonic-gate } 2356*7c478bd9Sstevel@tonic-gate return (first_item); /* this is EOD msg */ 2357*7c478bd9Sstevel@tonic-gate } 2358*7c478bd9Sstevel@tonic-gate 2359*7c478bd9Sstevel@tonic-gate if (ctlbuf.len >= sizeof (struct T_error_ack) && 2360*7c478bd9Sstevel@tonic-gate tea->PRIM_type == T_ERROR_ACK) { 2361*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("mibget %d gives " 2362*7c478bd9Sstevel@tonic-gate "T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = " 2363*7c478bd9Sstevel@tonic-gate "0x%lx\n"), j, tea->TLI_error, tea->UNIX_error); 2364*7c478bd9Sstevel@tonic-gate errno = (tea->TLI_error == TSYSERR) 2365*7c478bd9Sstevel@tonic-gate ? tea->UNIX_error : EPROTO; 2366*7c478bd9Sstevel@tonic-gate break; 2367*7c478bd9Sstevel@tonic-gate } 2368*7c478bd9Sstevel@tonic-gate 2369*7c478bd9Sstevel@tonic-gate if (getcode != MOREDATA || 2370*7c478bd9Sstevel@tonic-gate ctlbuf.len < sizeof (struct T_optmgmt_ack) || 2371*7c478bd9Sstevel@tonic-gate toa->PRIM_type != T_OPTMGMT_ACK || 2372*7c478bd9Sstevel@tonic-gate toa->MGMT_flags != T_SUCCESS) { 2373*7c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg(ctl) %d returned %d, " 2374*7c478bd9Sstevel@tonic-gate "ctlbuf.len = %d, PRIM_type = %ld\n", 2375*7c478bd9Sstevel@tonic-gate j, getcode, ctlbuf.len, toa->PRIM_type); 2376*7c478bd9Sstevel@tonic-gate if (toa->PRIM_type == T_OPTMGMT_ACK) { 2377*7c478bd9Sstevel@tonic-gate (void) printf("T_OPTMGMT_ACK: " 2378*7c478bd9Sstevel@tonic-gate "MGMT_flags = 0x%lx, req->len = %ld\n", 2379*7c478bd9Sstevel@tonic-gate toa->MGMT_flags, req->len); 2380*7c478bd9Sstevel@tonic-gate } 2381*7c478bd9Sstevel@tonic-gate errno = ENOMSG; 2382*7c478bd9Sstevel@tonic-gate break; 2383*7c478bd9Sstevel@tonic-gate } 2384*7c478bd9Sstevel@tonic-gate 2385*7c478bd9Sstevel@tonic-gate temp = malloc(sizeof (mib_item_t)); 2386*7c478bd9Sstevel@tonic-gate if (temp == NULL) { 2387*7c478bd9Sstevel@tonic-gate perror("mibget: malloc"); 2388*7c478bd9Sstevel@tonic-gate break; 2389*7c478bd9Sstevel@tonic-gate } 2390*7c478bd9Sstevel@tonic-gate if (last_item != NULL) 2391*7c478bd9Sstevel@tonic-gate last_item->next_item = temp; 2392*7c478bd9Sstevel@tonic-gate else 2393*7c478bd9Sstevel@tonic-gate first_item = temp; 2394*7c478bd9Sstevel@tonic-gate last_item = temp; 2395*7c478bd9Sstevel@tonic-gate last_item->next_item = NULL; 2396*7c478bd9Sstevel@tonic-gate last_item->group = req->level; 2397*7c478bd9Sstevel@tonic-gate last_item->mib_id = req->name; 2398*7c478bd9Sstevel@tonic-gate last_item->length = req->len; 2399*7c478bd9Sstevel@tonic-gate last_item->valp = malloc(req->len); 2400*7c478bd9Sstevel@tonic-gate if (verbose) { 2401*7c478bd9Sstevel@tonic-gate (void) printf("msg %d: group = %4ld mib_id = %5ld " 2402*7c478bd9Sstevel@tonic-gate "length = %ld\n", 2403*7c478bd9Sstevel@tonic-gate j, last_item->group, last_item->mib_id, 2404*7c478bd9Sstevel@tonic-gate last_item->length); 2405*7c478bd9Sstevel@tonic-gate } 2406*7c478bd9Sstevel@tonic-gate 2407*7c478bd9Sstevel@tonic-gate databuf.maxlen = last_item->length; 2408*7c478bd9Sstevel@tonic-gate databuf.buf = (char *)last_item->valp; 2409*7c478bd9Sstevel@tonic-gate databuf.len = 0; 2410*7c478bd9Sstevel@tonic-gate flags = 0; 2411*7c478bd9Sstevel@tonic-gate getcode = getmsg(sd, NULL, &databuf, &flags); 2412*7c478bd9Sstevel@tonic-gate if (getcode < 0) { 2413*7c478bd9Sstevel@tonic-gate perror("mibget: getmsg (data)"); 2414*7c478bd9Sstevel@tonic-gate break; 2415*7c478bd9Sstevel@tonic-gate } else if (getcode != 0) { 2416*7c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg(data) returned %d, " 2417*7c478bd9Sstevel@tonic-gate "databuf.maxlen = %d, databuf.len = %d\n", 2418*7c478bd9Sstevel@tonic-gate getcode, databuf.maxlen, databuf.len); 2419*7c478bd9Sstevel@tonic-gate break; 2420*7c478bd9Sstevel@tonic-gate } 2421*7c478bd9Sstevel@tonic-gate } 2422*7c478bd9Sstevel@tonic-gate 2423*7c478bd9Sstevel@tonic-gate /* 2424*7c478bd9Sstevel@tonic-gate * On error, free all the allocated mib_item_t objects. 2425*7c478bd9Sstevel@tonic-gate */ 2426*7c478bd9Sstevel@tonic-gate while (first_item != NULL) { 2427*7c478bd9Sstevel@tonic-gate last_item = first_item; 2428*7c478bd9Sstevel@tonic-gate first_item = first_item->next_item; 2429*7c478bd9Sstevel@tonic-gate free(last_item); 2430*7c478bd9Sstevel@tonic-gate } 2431*7c478bd9Sstevel@tonic-gate return (NULL); 2432*7c478bd9Sstevel@tonic-gate } 2433