17c478bd9Sstevel@tonic-gate /* 2*3f33f4f7Sjl138328 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 77c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 87c478bd9Sstevel@tonic-gate 97c478bd9Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */ 107c478bd9Sstevel@tonic-gate 117c478bd9Sstevel@tonic-gate /* 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1989, 1991, 1993 147c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 157c478bd9Sstevel@tonic-gate * 167c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 177c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 187c478bd9Sstevel@tonic-gate * are met: 197c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 207c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 217c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 227c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 237c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 247c478bd9Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 257c478bd9Sstevel@tonic-gate * must display the following acknowledgement: 267c478bd9Sstevel@tonic-gate * This product includes software developed by the University of 277c478bd9Sstevel@tonic-gate * California, Berkeley and its contributors. 287c478bd9Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors 297c478bd9Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 307c478bd9Sstevel@tonic-gate * without specific prior written permission. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 337c478bd9Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 347c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 357c478bd9Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 367c478bd9Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 377c478bd9Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 387c478bd9Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 397c478bd9Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 407c478bd9Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 417c478bd9Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 427c478bd9Sstevel@tonic-gate * SUCH DAMAGE. 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * @(#)route.c 8.6 (Berkeley) 4/28/95 457c478bd9Sstevel@tonic-gate * @(#)linkaddr.c 8.1 (Berkeley) 6/4/93 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #include <sys/param.h> 517c478bd9Sstevel@tonic-gate #include <sys/file.h> 527c478bd9Sstevel@tonic-gate #include <sys/socket.h> 537c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 54*3f33f4f7Sjl138328 #include <sys/stat.h> 557c478bd9Sstevel@tonic-gate #include <sys/stream.h> 567c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 57*3f33f4f7Sjl138328 #include <sys/tihdr.h> 58*3f33f4f7Sjl138328 #include <sys/types.h> 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate #include <net/if.h> 617c478bd9Sstevel@tonic-gate #include <net/route.h> 627c478bd9Sstevel@tonic-gate #include <net/if_dl.h> 637c478bd9Sstevel@tonic-gate #include <netinet/in.h> 647c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 657c478bd9Sstevel@tonic-gate #include <netdb.h> 667c478bd9Sstevel@tonic-gate #include <inet/mib2.h> 677c478bd9Sstevel@tonic-gate #include <inet/ip.h> 687c478bd9Sstevel@tonic-gate 69*3f33f4f7Sjl138328 #include <limits.h> 707c478bd9Sstevel@tonic-gate #include <locale.h> 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate #include <errno.h> 737c478bd9Sstevel@tonic-gate #include <unistd.h> 747c478bd9Sstevel@tonic-gate #include <stdio.h> 757c478bd9Sstevel@tonic-gate #include <stdlib.h> 767c478bd9Sstevel@tonic-gate #include <string.h> 777c478bd9Sstevel@tonic-gate #include <stropts.h> 787c478bd9Sstevel@tonic-gate #include <fcntl.h> 79*3f33f4f7Sjl138328 #include <setjmp.h> 80*3f33f4f7Sjl138328 #include <stdarg.h> 817c478bd9Sstevel@tonic-gate #include <assert.h> 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate static struct keytab { 847c478bd9Sstevel@tonic-gate char *kt_cp; 857c478bd9Sstevel@tonic-gate int kt_i; 867c478bd9Sstevel@tonic-gate } keywords[] = { 877c478bd9Sstevel@tonic-gate #define K_ADD 1 887c478bd9Sstevel@tonic-gate {"add", K_ADD}, 897c478bd9Sstevel@tonic-gate #define K_BLACKHOLE 2 907c478bd9Sstevel@tonic-gate {"blackhole", K_BLACKHOLE}, 917c478bd9Sstevel@tonic-gate #define K_CHANGE 3 927c478bd9Sstevel@tonic-gate {"change", K_CHANGE}, 937c478bd9Sstevel@tonic-gate #define K_CLONING 4 947c478bd9Sstevel@tonic-gate {"cloning", K_CLONING}, 957c478bd9Sstevel@tonic-gate #define K_DELETE 5 967c478bd9Sstevel@tonic-gate {"delete", K_DELETE}, 977c478bd9Sstevel@tonic-gate #define K_DST 6 987c478bd9Sstevel@tonic-gate {"dst", K_DST}, 997c478bd9Sstevel@tonic-gate #define K_EXPIRE 7 1007c478bd9Sstevel@tonic-gate {"expire", K_EXPIRE}, 1017c478bd9Sstevel@tonic-gate #define K_FLUSH 8 1027c478bd9Sstevel@tonic-gate {"flush", K_FLUSH}, 1037c478bd9Sstevel@tonic-gate #define K_GATEWAY 9 1047c478bd9Sstevel@tonic-gate {"gateway", K_GATEWAY}, 1057c478bd9Sstevel@tonic-gate #define K_GET 11 1067c478bd9Sstevel@tonic-gate {"get", K_GET}, 1077c478bd9Sstevel@tonic-gate #define K_HOPCOUNT 12 1087c478bd9Sstevel@tonic-gate {"hopcount", K_HOPCOUNT}, 1097c478bd9Sstevel@tonic-gate #define K_HOST 13 1107c478bd9Sstevel@tonic-gate {"host", K_HOST}, 1117c478bd9Sstevel@tonic-gate #define K_IFA 14 1127c478bd9Sstevel@tonic-gate {"ifa", K_IFA}, 1137c478bd9Sstevel@tonic-gate #define K_IFACE 15 1147c478bd9Sstevel@tonic-gate {"iface", K_IFACE}, 1157c478bd9Sstevel@tonic-gate #define K_IFP 16 1167c478bd9Sstevel@tonic-gate {"ifp", K_IFP}, 1177c478bd9Sstevel@tonic-gate #define K_INET 17 1187c478bd9Sstevel@tonic-gate {"inet", K_INET}, 1197c478bd9Sstevel@tonic-gate #define K_INET6 18 1207c478bd9Sstevel@tonic-gate {"inet6", K_INET6}, 1217c478bd9Sstevel@tonic-gate #define K_INTERFACE 19 1227c478bd9Sstevel@tonic-gate {"interface", K_INTERFACE}, 1237c478bd9Sstevel@tonic-gate #define K_LINK 20 1247c478bd9Sstevel@tonic-gate {"link", K_LINK}, 1257c478bd9Sstevel@tonic-gate #define K_LOCK 21 1267c478bd9Sstevel@tonic-gate {"lock", K_LOCK}, 1277c478bd9Sstevel@tonic-gate #define K_LOCKREST 22 1287c478bd9Sstevel@tonic-gate {"lockrest", K_LOCKREST}, 1297c478bd9Sstevel@tonic-gate #define K_MASK 23 1307c478bd9Sstevel@tonic-gate {"mask", K_MASK}, 1317c478bd9Sstevel@tonic-gate #define K_MONITOR 24 1327c478bd9Sstevel@tonic-gate {"monitor", K_MONITOR}, 1337c478bd9Sstevel@tonic-gate #define K_MTU 25 1347c478bd9Sstevel@tonic-gate {"mtu", K_MTU}, 1357c478bd9Sstevel@tonic-gate #define K_NET 26 1367c478bd9Sstevel@tonic-gate {"net", K_NET}, 1377c478bd9Sstevel@tonic-gate #define K_NETMASK 27 1387c478bd9Sstevel@tonic-gate {"netmask", K_NETMASK}, 1397c478bd9Sstevel@tonic-gate #define K_NOSTATIC 28 1407c478bd9Sstevel@tonic-gate {"nostatic", K_NOSTATIC}, 1417c478bd9Sstevel@tonic-gate #define K_PRIVATE 29 1427c478bd9Sstevel@tonic-gate {"private", K_PRIVATE}, 1437c478bd9Sstevel@tonic-gate #define K_PROTO1 30 1447c478bd9Sstevel@tonic-gate {"proto1", K_PROTO1}, 1457c478bd9Sstevel@tonic-gate #define K_PROTO2 31 1467c478bd9Sstevel@tonic-gate {"proto2", K_PROTO2}, 1477c478bd9Sstevel@tonic-gate #define K_RECVPIPE 32 1487c478bd9Sstevel@tonic-gate {"recvpipe", K_RECVPIPE}, 1497c478bd9Sstevel@tonic-gate #define K_REJECT 33 1507c478bd9Sstevel@tonic-gate {"reject", K_REJECT}, 1517c478bd9Sstevel@tonic-gate #define K_RTT 34 1527c478bd9Sstevel@tonic-gate {"rtt", K_RTT}, 1537c478bd9Sstevel@tonic-gate #define K_RTTVAR 35 1547c478bd9Sstevel@tonic-gate {"rttvar", K_RTTVAR}, 1557c478bd9Sstevel@tonic-gate #define K_SA 36 1567c478bd9Sstevel@tonic-gate {"sa", K_SA}, 1577c478bd9Sstevel@tonic-gate #define K_SENDPIPE 37 1587c478bd9Sstevel@tonic-gate {"sendpipe", K_SENDPIPE}, 1597c478bd9Sstevel@tonic-gate #define K_SSTHRESH 38 1607c478bd9Sstevel@tonic-gate {"ssthresh", K_SSTHRESH}, 1617c478bd9Sstevel@tonic-gate #define K_STATIC 39 1627c478bd9Sstevel@tonic-gate {"static", K_STATIC}, 1637c478bd9Sstevel@tonic-gate #define K_XRESOLVE 40 1647c478bd9Sstevel@tonic-gate {"xresolve", K_XRESOLVE}, 1657c478bd9Sstevel@tonic-gate #define K_MULTIRT 41 1667c478bd9Sstevel@tonic-gate {"multirt", K_MULTIRT}, 1677c478bd9Sstevel@tonic-gate #define K_SETSRC 42 1687c478bd9Sstevel@tonic-gate {"setsrc", K_SETSRC}, 169*3f33f4f7Sjl138328 #define K_SHOW 43 170*3f33f4f7Sjl138328 {"show", K_SHOW}, 1717c478bd9Sstevel@tonic-gate {0, 0} 1727c478bd9Sstevel@tonic-gate }; 1737c478bd9Sstevel@tonic-gate 174*3f33f4f7Sjl138328 /* 175*3f33f4f7Sjl138328 * Size of buffers used to hold command lines from the saved route file as 176*3f33f4f7Sjl138328 * well as error strings. 177*3f33f4f7Sjl138328 */ 178*3f33f4f7Sjl138328 #define BUF_SIZE 2048 179*3f33f4f7Sjl138328 180*3f33f4f7Sjl138328 typedef union sockunion { 1817c478bd9Sstevel@tonic-gate struct sockaddr sa; 1827c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 1837c478bd9Sstevel@tonic-gate struct sockaddr_dl sdl; 1847c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 185*3f33f4f7Sjl138328 } su_t; 186*3f33f4f7Sjl138328 187*3f33f4f7Sjl138328 /* 188*3f33f4f7Sjl138328 * This structure represents the digested information from parsing arguments 189*3f33f4f7Sjl138328 * to route add, change, delete, and get. 190*3f33f4f7Sjl138328 * 191*3f33f4f7Sjl138328 */ 192*3f33f4f7Sjl138328 typedef struct rtcmd_irep { 193*3f33f4f7Sjl138328 int ri_cmd; 194*3f33f4f7Sjl138328 int ri_flags; 195*3f33f4f7Sjl138328 int ri_af; 196*3f33f4f7Sjl138328 int ri_masklen; 197*3f33f4f7Sjl138328 ulong_t ri_inits; 198*3f33f4f7Sjl138328 struct rt_metrics ri_metrics; 199*3f33f4f7Sjl138328 int ri_addrs; 200*3f33f4f7Sjl138328 su_t ri_dst; 201*3f33f4f7Sjl138328 char *ri_dest_str; 202*3f33f4f7Sjl138328 su_t ri_src; 203*3f33f4f7Sjl138328 su_t ri_gate; 204*3f33f4f7Sjl138328 struct hostent *ri_gate_hp; 205*3f33f4f7Sjl138328 char *ri_gate_str; 206*3f33f4f7Sjl138328 su_t ri_mask; 207*3f33f4f7Sjl138328 su_t ri_ifa; 208*3f33f4f7Sjl138328 su_t ri_ifp; 209*3f33f4f7Sjl138328 char *ri_ifp_str; 210*3f33f4f7Sjl138328 } rtcmd_irep_t; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate typedef struct mib_item_s { 2137c478bd9Sstevel@tonic-gate struct mib_item_s *next_item; 2147c478bd9Sstevel@tonic-gate long group; 2157c478bd9Sstevel@tonic-gate long mib_id; 2167c478bd9Sstevel@tonic-gate long length; 2177c478bd9Sstevel@tonic-gate intmax_t *valp; 2187c478bd9Sstevel@tonic-gate } mib_item_t; 2197c478bd9Sstevel@tonic-gate 220*3f33f4f7Sjl138328 typedef enum { 221*3f33f4f7Sjl138328 ADDR_TYPE_ANY, 222*3f33f4f7Sjl138328 ADDR_TYPE_HOST, 223*3f33f4f7Sjl138328 ADDR_TYPE_NET 224*3f33f4f7Sjl138328 } addr_type_t; 2257c478bd9Sstevel@tonic-gate 226*3f33f4f7Sjl138328 typedef enum { 227*3f33f4f7Sjl138328 SEARCH_MODE_NULL, 228*3f33f4f7Sjl138328 SEARCH_MODE_PRINT, 229*3f33f4f7Sjl138328 SEARCH_MODE_DEL 230*3f33f4f7Sjl138328 } search_mode_t; 231*3f33f4f7Sjl138328 232*3f33f4f7Sjl138328 static boolean_t args_to_rtcmd(rtcmd_irep_t *rcip, char **argv, 233*3f33f4f7Sjl138328 char *cmd_string); 2347c478bd9Sstevel@tonic-gate static void bprintf(FILE *fp, int b, char *s); 235*3f33f4f7Sjl138328 static boolean_t compare_rtcmd(rtcmd_irep_t *srch_rt, 236*3f33f4f7Sjl138328 rtcmd_irep_t *file_rt); 2377c478bd9Sstevel@tonic-gate static void delRouteEntry(mib2_ipRouteEntry_t *rp, 2387c478bd9Sstevel@tonic-gate mib2_ipv6RouteEntry_t *rp6, int seqno); 239*3f33f4f7Sjl138328 static void del_rtcmd_irep(rtcmd_irep_t *rcip); 2407c478bd9Sstevel@tonic-gate static void flushroutes(int argc, char *argv[]); 241*3f33f4f7Sjl138328 static boolean_t getaddr(rtcmd_irep_t *rcip, int which, char *s, 242*3f33f4f7Sjl138328 addr_type_t atype); 2437c478bd9Sstevel@tonic-gate static boolean_t in6_getaddr(char *s, struct sockaddr_in6 *sin6, 2447c478bd9Sstevel@tonic-gate int *plenp, struct hostent **hpp); 2457c478bd9Sstevel@tonic-gate static boolean_t in_getaddr(char *s, struct sockaddr_in *sin, 246*3f33f4f7Sjl138328 int *plenp, int which, struct hostent **hpp, addr_type_t atype, 247*3f33f4f7Sjl138328 rtcmd_irep_t *rcip); 2487c478bd9Sstevel@tonic-gate static int in_getprefixlen(char *addr, int max_plen); 2497c478bd9Sstevel@tonic-gate static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 2507c478bd9Sstevel@tonic-gate uchar_t *mask); 251*3f33f4f7Sjl138328 static void inet_makenetandmask(rtcmd_irep_t *rcip, in_addr_t net, 2527c478bd9Sstevel@tonic-gate struct sockaddr_in *sin); 2537c478bd9Sstevel@tonic-gate static in_addr_t inet_makesubnetmask(in_addr_t addr, in_addr_t mask); 2547c478bd9Sstevel@tonic-gate static int keyword(char *cp); 2557c478bd9Sstevel@tonic-gate static void link_addr(const char *addr, struct sockaddr_dl *sdl); 2567c478bd9Sstevel@tonic-gate static char *link_ntoa(const struct sockaddr_dl *sdl); 2577c478bd9Sstevel@tonic-gate static mib_item_t *mibget(int sd); 2587c478bd9Sstevel@tonic-gate static char *netname(struct sockaddr *sa); 259*3f33f4f7Sjl138328 static int newroute(char **argv); 260*3f33f4f7Sjl138328 static rtcmd_irep_t *new_rtcmd_irep(void); 2617c478bd9Sstevel@tonic-gate static void pmsg_addrs(char *cp, int addrs); 2627c478bd9Sstevel@tonic-gate static void pmsg_common(struct rt_msghdr *rtm); 263*3f33f4f7Sjl138328 static void print_getmsg(rtcmd_irep_t *req_rt, 264*3f33f4f7Sjl138328 struct rt_msghdr *rtm, int msglen); 265*3f33f4f7Sjl138328 static void print_rtcmd_short(FILE *to, rtcmd_irep_t *rcip, 266*3f33f4f7Sjl138328 boolean_t gw_good, boolean_t to_saved); 2677c478bd9Sstevel@tonic-gate static void print_rtmsg(struct rt_msghdr *rtm, int msglen); 2687c478bd9Sstevel@tonic-gate static void quit(char *s, int err); 2697c478bd9Sstevel@tonic-gate static char *routename(struct sockaddr *sa); 2707c478bd9Sstevel@tonic-gate static void rtmonitor(int argc, char *argv[]); 271*3f33f4f7Sjl138328 static int rtmsg(rtcmd_irep_t *rcip); 2727c478bd9Sstevel@tonic-gate static int salen(struct sockaddr *sa); 273*3f33f4f7Sjl138328 static void save_route(int argc, char **argv); 274*3f33f4f7Sjl138328 static void save_string(char **dst, char *src); 275*3f33f4f7Sjl138328 static int search_rtfile(FILE *fp, FILE *temp_fp, rtcmd_irep_t *rt, 276*3f33f4f7Sjl138328 search_mode_t mode); 277*3f33f4f7Sjl138328 static void set_metric(rtcmd_irep_t *rcip, char *value, int key, 278*3f33f4f7Sjl138328 boolean_t lock); 279*3f33f4f7Sjl138328 static int show_saved_routes(int argc); 2807c478bd9Sstevel@tonic-gate static void sockaddr(char *addr, struct sockaddr *sa); 281*3f33f4f7Sjl138328 static void sodump(su_t *su, char *which); 282*3f33f4f7Sjl138328 static void syntax_arg_missing(char *keyword); 283*3f33f4f7Sjl138328 static void syntax_bad_keyword(char *keyword); 284*3f33f4f7Sjl138328 static void syntax_error(char *err, ...); 2857c478bd9Sstevel@tonic-gate static void usage(char *cp); 286*3f33f4f7Sjl138328 static void write_to_rtfile(FILE *fp, int argc, char **argv); 2877c478bd9Sstevel@tonic-gate 288*3f33f4f7Sjl138328 static pid_t pid; 2897c478bd9Sstevel@tonic-gate static int s; 290*3f33f4f7Sjl138328 static boolean_t nflag; 2917c478bd9Sstevel@tonic-gate static int af = AF_INET; 2927c478bd9Sstevel@tonic-gate static boolean_t qflag, tflag; 293*3f33f4f7Sjl138328 static boolean_t verbose; 294*3f33f4f7Sjl138328 static boolean_t debugonly; 2957c478bd9Sstevel@tonic-gate static boolean_t fflag; 296*3f33f4f7Sjl138328 static boolean_t perm_flag; 297*3f33f4f7Sjl138328 static char perm_file_sfx[] = "/etc/inet/static_routes"; 298*3f33f4f7Sjl138328 static char *perm_file; 299*3f33f4f7Sjl138328 static char *root_dir; 300*3f33f4f7Sjl138328 static char temp_file_sfx[] = "/etc/inet/static_routes.tmp"; 301*3f33f4f7Sjl138328 static char *temp_file; 302*3f33f4f7Sjl138328 303*3f33f4f7Sjl138328 /* 304*3f33f4f7Sjl138328 * WARNING: 305*3f33f4f7Sjl138328 * This next variable indicates whether certain functions exit when an error 306*3f33f4f7Sjl138328 * is detected in the user input. Currently, exit_on_error is only set false 307*3f33f4f7Sjl138328 * in search_rtfile(), when argument are being parsed. Only those functions 308*3f33f4f7Sjl138328 * used by search_rtfile() to parse its arguments are designed to work in 309*3f33f4f7Sjl138328 * both modes. Take particular care in setting this false to ensure that any 310*3f33f4f7Sjl138328 * functions you call that might act on this flag properly return errors when 311*3f33f4f7Sjl138328 * exit_on_error is false. 312*3f33f4f7Sjl138328 */ 313*3f33f4f7Sjl138328 static int exit_on_error = B_TRUE; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate static struct { 3167c478bd9Sstevel@tonic-gate struct rt_msghdr m_rtm; 3177c478bd9Sstevel@tonic-gate char m_space[512]; 3187c478bd9Sstevel@tonic-gate } m_rtmsg; 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate /* 3217c478bd9Sstevel@tonic-gate * Sizes of data structures extracted from the base mib. 3227c478bd9Sstevel@tonic-gate * This allows the size of the tables entries to grow while preserving 3237c478bd9Sstevel@tonic-gate * binary compatibility. 3247c478bd9Sstevel@tonic-gate */ 3257c478bd9Sstevel@tonic-gate static int ipRouteEntrySize; 3267c478bd9Sstevel@tonic-gate static int ipv6RouteEntrySize; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate #define ROUNDUP_LONG(a) \ 3297c478bd9Sstevel@tonic-gate ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long)) 3307c478bd9Sstevel@tonic-gate #define ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n))) 3317c478bd9Sstevel@tonic-gate #define C(x) ((x) & 0xff) 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate /* 3347c478bd9Sstevel@tonic-gate * return values from in_getprefixlen() 3357c478bd9Sstevel@tonic-gate */ 3367c478bd9Sstevel@tonic-gate #define BAD_ADDR -1 /* prefix is invalid */ 3377c478bd9Sstevel@tonic-gate #define NO_PREFIX -2 /* no prefix was found */ 3387c478bd9Sstevel@tonic-gate 339*3f33f4f7Sjl138328 3407c478bd9Sstevel@tonic-gate void 3417c478bd9Sstevel@tonic-gate usage(char *cp) 3427c478bd9Sstevel@tonic-gate { 343*3f33f4f7Sjl138328 if (cp != NULL) { 3447c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: botched keyword: %s\n"), 3457c478bd9Sstevel@tonic-gate cp); 346*3f33f4f7Sjl138328 } 347*3f33f4f7Sjl138328 (void) fprintf(stderr, gettext("usage: route [ -fnpqv ] " 348*3f33f4f7Sjl138328 "[ -R <root-dir> ] cmd [[ -<qualifers> ] args ]\n")); 3497c478bd9Sstevel@tonic-gate exit(1); 3507c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 353*3f33f4f7Sjl138328 /*PRINTFLIKE1*/ 354*3f33f4f7Sjl138328 void 355*3f33f4f7Sjl138328 syntax_error(char *err, ...) 356*3f33f4f7Sjl138328 { 357*3f33f4f7Sjl138328 va_list args; 358*3f33f4f7Sjl138328 359*3f33f4f7Sjl138328 if (exit_on_error) { 360*3f33f4f7Sjl138328 va_start(args, err); 361*3f33f4f7Sjl138328 (void) vfprintf(stderr, err, args); 362*3f33f4f7Sjl138328 va_end(args); 363*3f33f4f7Sjl138328 exit(1); 364*3f33f4f7Sjl138328 } 365*3f33f4f7Sjl138328 /* NOTREACHED */ 366*3f33f4f7Sjl138328 } 367*3f33f4f7Sjl138328 368*3f33f4f7Sjl138328 void 369*3f33f4f7Sjl138328 syntax_bad_keyword(char *keyword) 370*3f33f4f7Sjl138328 { 371*3f33f4f7Sjl138328 syntax_error(gettext("route: botched keyword: %s\n"), keyword); 372*3f33f4f7Sjl138328 } 373*3f33f4f7Sjl138328 374*3f33f4f7Sjl138328 void 375*3f33f4f7Sjl138328 syntax_arg_missing(char *keyword) 376*3f33f4f7Sjl138328 { 377*3f33f4f7Sjl138328 syntax_error(gettext("route: argument required following keyword %s\n"), 378*3f33f4f7Sjl138328 keyword); 379*3f33f4f7Sjl138328 } 380*3f33f4f7Sjl138328 3817c478bd9Sstevel@tonic-gate void 3827c478bd9Sstevel@tonic-gate quit(char *s, int sverrno) 3837c478bd9Sstevel@tonic-gate { 3847c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "route: "); 3857c478bd9Sstevel@tonic-gate if (s != NULL) 3867c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", s); 3877c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", strerror(sverrno)); 3887c478bd9Sstevel@tonic-gate exit(sverrno); 3897c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate int 3937c478bd9Sstevel@tonic-gate main(int argc, char **argv) 3947c478bd9Sstevel@tonic-gate { 3957c478bd9Sstevel@tonic-gate extern int optind; 396*3f33f4f7Sjl138328 extern char *optarg; 3977c478bd9Sstevel@tonic-gate int ch; 3987c478bd9Sstevel@tonic-gate int key; 399*3f33f4f7Sjl138328 int rval; 400*3f33f4f7Sjl138328 size_t size; 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 4057c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 4067c478bd9Sstevel@tonic-gate #endif 4077c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate if (argc < 2) 4107c478bd9Sstevel@tonic-gate usage((char *)NULL); 4117c478bd9Sstevel@tonic-gate 412*3f33f4f7Sjl138328 while ((ch = getopt(argc, argv, "R:nqdtvfp")) != EOF) { 4137c478bd9Sstevel@tonic-gate switch (ch) { 4147c478bd9Sstevel@tonic-gate case 'n': 4157c478bd9Sstevel@tonic-gate nflag = B_TRUE; 4167c478bd9Sstevel@tonic-gate break; 4177c478bd9Sstevel@tonic-gate case 'q': 4187c478bd9Sstevel@tonic-gate qflag = B_TRUE; 4197c478bd9Sstevel@tonic-gate break; 4207c478bd9Sstevel@tonic-gate case 'v': 4217c478bd9Sstevel@tonic-gate verbose = B_TRUE; 4227c478bd9Sstevel@tonic-gate break; 4237c478bd9Sstevel@tonic-gate case 't': 4247c478bd9Sstevel@tonic-gate tflag = B_TRUE; 4257c478bd9Sstevel@tonic-gate break; 4267c478bd9Sstevel@tonic-gate case 'd': 4277c478bd9Sstevel@tonic-gate debugonly = B_TRUE; 4287c478bd9Sstevel@tonic-gate break; 4297c478bd9Sstevel@tonic-gate case 'f': 4307c478bd9Sstevel@tonic-gate fflag = B_TRUE; 4317c478bd9Sstevel@tonic-gate break; 432*3f33f4f7Sjl138328 case 'p': 433*3f33f4f7Sjl138328 perm_flag = B_TRUE; 434*3f33f4f7Sjl138328 break; 435*3f33f4f7Sjl138328 case 'R': 436*3f33f4f7Sjl138328 root_dir = optarg; 437*3f33f4f7Sjl138328 break; 4387c478bd9Sstevel@tonic-gate case '?': 4397c478bd9Sstevel@tonic-gate default: 4407c478bd9Sstevel@tonic-gate usage((char *)NULL); 4417c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate argc -= optind; 4457c478bd9Sstevel@tonic-gate argv += optind; 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate pid = getpid(); 4487c478bd9Sstevel@tonic-gate if (tflag) 4497c478bd9Sstevel@tonic-gate s = open("/dev/null", O_WRONLY); 4507c478bd9Sstevel@tonic-gate else 4517c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, 0); 4527c478bd9Sstevel@tonic-gate if (s < 0) 4537c478bd9Sstevel@tonic-gate quit("socket", errno); 454*3f33f4f7Sjl138328 455*3f33f4f7Sjl138328 /* 456*3f33f4f7Sjl138328 * Handle the -p and -R flags. The -R flag only applies 457*3f33f4f7Sjl138328 * when the -p flag is set. 458*3f33f4f7Sjl138328 */ 459*3f33f4f7Sjl138328 if (root_dir == NULL) { 460*3f33f4f7Sjl138328 perm_file = perm_file_sfx; 461*3f33f4f7Sjl138328 temp_file = temp_file_sfx; 462*3f33f4f7Sjl138328 } else { 463*3f33f4f7Sjl138328 size = strlen(root_dir) + sizeof (perm_file_sfx); 464*3f33f4f7Sjl138328 perm_file = malloc(size); 465*3f33f4f7Sjl138328 if (perm_file == NULL) 466*3f33f4f7Sjl138328 quit("malloc", errno); 467*3f33f4f7Sjl138328 (void) snprintf(perm_file, size, "%s%s", root_dir, 468*3f33f4f7Sjl138328 perm_file_sfx); 469*3f33f4f7Sjl138328 size = strlen(root_dir) + sizeof (temp_file_sfx); 470*3f33f4f7Sjl138328 temp_file = malloc(size); 471*3f33f4f7Sjl138328 if (temp_file == NULL) 472*3f33f4f7Sjl138328 quit("malloc", errno); 473*3f33f4f7Sjl138328 (void) snprintf(temp_file, size, "%s%s", root_dir, 474*3f33f4f7Sjl138328 temp_file_sfx); 475*3f33f4f7Sjl138328 } 476*3f33f4f7Sjl138328 4777c478bd9Sstevel@tonic-gate if (fflag) { 4787c478bd9Sstevel@tonic-gate /* 4797c478bd9Sstevel@tonic-gate * Accept an address family keyword after the -f. Since the 4807c478bd9Sstevel@tonic-gate * default address family is AF_INET, reassign af only for the 4817c478bd9Sstevel@tonic-gate * other valid address families. 4827c478bd9Sstevel@tonic-gate */ 4837c478bd9Sstevel@tonic-gate if (*argv != NULL) { 4847c478bd9Sstevel@tonic-gate switch (key = keyword(*argv)) { 4857c478bd9Sstevel@tonic-gate case K_INET: 4867c478bd9Sstevel@tonic-gate case K_INET6: 4877c478bd9Sstevel@tonic-gate if (key == K_INET6) 4887c478bd9Sstevel@tonic-gate af = AF_INET6; 4897c478bd9Sstevel@tonic-gate /* Skip over the address family parameter. */ 4907c478bd9Sstevel@tonic-gate argc--; 4917c478bd9Sstevel@tonic-gate argv++; 4927c478bd9Sstevel@tonic-gate break; 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate } 495*3f33f4f7Sjl138328 if (perm_flag && root_dir != NULL) { 496*3f33f4f7Sjl138328 /* 497*3f33f4f7Sjl138328 * Act only on the file. 498*3f33f4f7Sjl138328 */ 499*3f33f4f7Sjl138328 save_route(argc, argv); 500*3f33f4f7Sjl138328 } else { 5017c478bd9Sstevel@tonic-gate flushroutes(0, NULL); 5027c478bd9Sstevel@tonic-gate } 503*3f33f4f7Sjl138328 } 504*3f33f4f7Sjl138328 5057c478bd9Sstevel@tonic-gate if (*argv != NULL) { 506*3f33f4f7Sjl138328 fflag = 0; 5077c478bd9Sstevel@tonic-gate switch (keyword(*argv)) { 5087c478bd9Sstevel@tonic-gate case K_GET: 5097c478bd9Sstevel@tonic-gate case K_CHANGE: 5107c478bd9Sstevel@tonic-gate case K_ADD: 5117c478bd9Sstevel@tonic-gate case K_DELETE: 512*3f33f4f7Sjl138328 if (perm_flag && root_dir != NULL) { 513*3f33f4f7Sjl138328 /* 514*3f33f4f7Sjl138328 * Act only on the file. 515*3f33f4f7Sjl138328 */ 516*3f33f4f7Sjl138328 rval = 0; 517*3f33f4f7Sjl138328 } else { 518*3f33f4f7Sjl138328 rval = newroute(argv); 519*3f33f4f7Sjl138328 } 520*3f33f4f7Sjl138328 if (perm_flag && (rval == 0 || rval == EEXIST || 521*3f33f4f7Sjl138328 rval == ESRCH)) { 522*3f33f4f7Sjl138328 save_route(argc, argv); 523*3f33f4f7Sjl138328 return (0); 524*3f33f4f7Sjl138328 } 525*3f33f4f7Sjl138328 return (rval); 526*3f33f4f7Sjl138328 case K_SHOW: 527*3f33f4f7Sjl138328 if (perm_flag) { 528*3f33f4f7Sjl138328 return (show_saved_routes(argc)); 529*3f33f4f7Sjl138328 } else { 530*3f33f4f7Sjl138328 syntax_error(gettext( 531*3f33f4f7Sjl138328 "route: show command requires -p")); 532*3f33f4f7Sjl138328 } 533*3f33f4f7Sjl138328 /* NOTREACHED */ 5347c478bd9Sstevel@tonic-gate case K_MONITOR: 5357c478bd9Sstevel@tonic-gate rtmonitor(argc, argv); 5367c478bd9Sstevel@tonic-gate /* NOTREACHED */ 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate case K_FLUSH: 5397c478bd9Sstevel@tonic-gate flushroutes(argc, argv); 540*3f33f4f7Sjl138328 if (perm_flag) { 541*3f33f4f7Sjl138328 fflag = 1; 542*3f33f4f7Sjl138328 save_route(argc, argv); 543*3f33f4f7Sjl138328 } 544*3f33f4f7Sjl138328 return (0); 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate if (!fflag) 5487c478bd9Sstevel@tonic-gate usage(*argv); 5497c478bd9Sstevel@tonic-gate return (0); 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate /* 5537c478bd9Sstevel@tonic-gate * Purge all entries in the routing tables not 5547c478bd9Sstevel@tonic-gate * associated with network interfaces. 5557c478bd9Sstevel@tonic-gate */ 5567c478bd9Sstevel@tonic-gate void 5577c478bd9Sstevel@tonic-gate flushroutes(int argc, char *argv[]) 5587c478bd9Sstevel@tonic-gate { 5597c478bd9Sstevel@tonic-gate int seqno; 5607c478bd9Sstevel@tonic-gate int sd; /* mib stream */ 5617c478bd9Sstevel@tonic-gate mib_item_t *item; 5627c478bd9Sstevel@tonic-gate mib2_ipRouteEntry_t *rp; 5637c478bd9Sstevel@tonic-gate mib2_ipv6RouteEntry_t *rp6; 5647c478bd9Sstevel@tonic-gate int oerrno; 5657c478bd9Sstevel@tonic-gate int off = 0; 5667c478bd9Sstevel@tonic-gate int on = 1; 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off, 5697c478bd9Sstevel@tonic-gate sizeof (off)) < 0) 5707c478bd9Sstevel@tonic-gate quit("setsockopt", errno); 5717c478bd9Sstevel@tonic-gate if (argc > 1) { 5727c478bd9Sstevel@tonic-gate argv++; 5737c478bd9Sstevel@tonic-gate if (argc == 2 && **argv == '-') { 5747c478bd9Sstevel@tonic-gate /* 5757c478bd9Sstevel@tonic-gate * The address family (preceded by a dash) may be used 5767c478bd9Sstevel@tonic-gate * to flush the routes of that particular family. 5777c478bd9Sstevel@tonic-gate */ 5787c478bd9Sstevel@tonic-gate switch (keyword(*argv + 1)) { 5797c478bd9Sstevel@tonic-gate case K_INET: 5807c478bd9Sstevel@tonic-gate af = AF_INET; 5817c478bd9Sstevel@tonic-gate break; 5827c478bd9Sstevel@tonic-gate case K_LINK: 5837c478bd9Sstevel@tonic-gate af = AF_LINK; 5847c478bd9Sstevel@tonic-gate break; 5857c478bd9Sstevel@tonic-gate case K_INET6: 5867c478bd9Sstevel@tonic-gate af = AF_INET6; 5877c478bd9Sstevel@tonic-gate break; 5887c478bd9Sstevel@tonic-gate default: 5897c478bd9Sstevel@tonic-gate usage(*argv); 5907c478bd9Sstevel@tonic-gate /* NOTREACHED */ 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate } else { 5937c478bd9Sstevel@tonic-gate usage(*argv); 5947c478bd9Sstevel@tonic-gate } 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate sd = open("/dev/ip", O_RDWR); 5977c478bd9Sstevel@tonic-gate oerrno = errno; 5987c478bd9Sstevel@tonic-gate if (sd < 0) { 5997c478bd9Sstevel@tonic-gate switch (errno) { 6007c478bd9Sstevel@tonic-gate case EACCES: 6017c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6027c478bd9Sstevel@tonic-gate gettext("route: flush: insufficient privileges\n")); 6037c478bd9Sstevel@tonic-gate exit(oerrno); 6047c478bd9Sstevel@tonic-gate /* NOTREACHED */ 6057c478bd9Sstevel@tonic-gate default: 6067c478bd9Sstevel@tonic-gate quit(gettext("can't open mib stream"), oerrno); 6077c478bd9Sstevel@tonic-gate /* NOTREACHED */ 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate if ((item = mibget(sd)) == NULL) 6117c478bd9Sstevel@tonic-gate quit("mibget", errno); 6127c478bd9Sstevel@tonic-gate if (verbose) { 6137c478bd9Sstevel@tonic-gate (void) printf("Examining routing table from " 6147c478bd9Sstevel@tonic-gate "T_SVR4_OPTMGMT_REQ\n"); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate seqno = 0; /* ??? */ 6177c478bd9Sstevel@tonic-gate switch (af) { 6187c478bd9Sstevel@tonic-gate case AF_INET: 6197c478bd9Sstevel@tonic-gate /* Extract ipRouteEntrySize */ 6207c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 6217c478bd9Sstevel@tonic-gate if (item->mib_id != 0) 6227c478bd9Sstevel@tonic-gate continue; 6237c478bd9Sstevel@tonic-gate if (item->group == MIB2_IP) { 6247c478bd9Sstevel@tonic-gate ipRouteEntrySize = 6257c478bd9Sstevel@tonic-gate ((mib2_ip_t *)item->valp)->ipRouteEntrySize; 6267c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(ipRouteEntrySize, 6277c478bd9Sstevel@tonic-gate sizeof (mib2_ipRouteEntry_t *))); 6287c478bd9Sstevel@tonic-gate break; 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate if (ipRouteEntrySize == 0) { 6327c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6337c478bd9Sstevel@tonic-gate gettext("ipRouteEntrySize can't be determined.\n")); 6347c478bd9Sstevel@tonic-gate exit(1); 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 6377c478bd9Sstevel@tonic-gate /* 6387c478bd9Sstevel@tonic-gate * skip all the other trash that comes up the mib stream 6397c478bd9Sstevel@tonic-gate */ 6407c478bd9Sstevel@tonic-gate if (item->group != MIB2_IP || 6417c478bd9Sstevel@tonic-gate item->mib_id != MIB2_IP_ROUTE) 6427c478bd9Sstevel@tonic-gate continue; 6437c478bd9Sstevel@tonic-gate for (rp = (mib2_ipRouteEntry_t *)item->valp; 6447c478bd9Sstevel@tonic-gate (char *)rp < (char *)item->valp + item->length; 6457c478bd9Sstevel@tonic-gate /* LINTED */ 6467c478bd9Sstevel@tonic-gate rp = (mib2_ipRouteEntry_t *) 6477c478bd9Sstevel@tonic-gate ((char *)rp + ipRouteEntrySize)) { 6487c478bd9Sstevel@tonic-gate delRouteEntry(rp, NULL, seqno); 6497c478bd9Sstevel@tonic-gate seqno++; 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate break; 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate break; 6547c478bd9Sstevel@tonic-gate case AF_INET6: 6557c478bd9Sstevel@tonic-gate /* Extract ipv6RouteEntrySize */ 6567c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 6577c478bd9Sstevel@tonic-gate if (item->mib_id != 0) 6587c478bd9Sstevel@tonic-gate continue; 6597c478bd9Sstevel@tonic-gate if (item->group == MIB2_IP6) { 6607c478bd9Sstevel@tonic-gate ipv6RouteEntrySize = 6617c478bd9Sstevel@tonic-gate ((mib2_ipv6IfStatsEntry_t *)item->valp)-> 6627c478bd9Sstevel@tonic-gate ipv6RouteEntrySize; 6637c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(ipv6RouteEntrySize, 6647c478bd9Sstevel@tonic-gate sizeof (mib2_ipv6RouteEntry_t *))); 6657c478bd9Sstevel@tonic-gate break; 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate if (ipv6RouteEntrySize == 0) { 6697c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6707c478bd9Sstevel@tonic-gate "ipv6RouteEntrySize cannot be determined.\n")); 6717c478bd9Sstevel@tonic-gate exit(1); 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 6747c478bd9Sstevel@tonic-gate /* 6757c478bd9Sstevel@tonic-gate * skip all the other trash that comes up the mib stream 6767c478bd9Sstevel@tonic-gate */ 6777c478bd9Sstevel@tonic-gate if (item->group != MIB2_IP6 || 6787c478bd9Sstevel@tonic-gate item->mib_id != MIB2_IP6_ROUTE) 6797c478bd9Sstevel@tonic-gate continue; 6807c478bd9Sstevel@tonic-gate for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp; 6817c478bd9Sstevel@tonic-gate (char *)rp6 < (char *)item->valp + item->length; 6827c478bd9Sstevel@tonic-gate /* LINTED */ 6837c478bd9Sstevel@tonic-gate rp6 = (mib2_ipv6RouteEntry_t *) 6847c478bd9Sstevel@tonic-gate ((char *)rp6 + ipv6RouteEntrySize)) { 6857c478bd9Sstevel@tonic-gate delRouteEntry(NULL, rp6, seqno); 6867c478bd9Sstevel@tonic-gate seqno++; 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate break; 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate break; 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, 6947c478bd9Sstevel@tonic-gate sizeof (on)) < 0) 6957c478bd9Sstevel@tonic-gate quit("setsockopt", errno); 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate /* 6997c478bd9Sstevel@tonic-gate * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or 7007c478bd9Sstevel@tonic-gate * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in 7017c478bd9Sstevel@tonic-gate * order to facilitate the flushing of RTF_GATEWAY routes. 7027c478bd9Sstevel@tonic-gate */ 7037c478bd9Sstevel@tonic-gate static void 7047c478bd9Sstevel@tonic-gate delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno) 7057c478bd9Sstevel@tonic-gate { 7067c478bd9Sstevel@tonic-gate char *cp; 7077c478bd9Sstevel@tonic-gate int ire_type; 7087c478bd9Sstevel@tonic-gate int rlen; 7097c478bd9Sstevel@tonic-gate struct rt_msghdr *rtm; 7107c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 7117c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 7127c478bd9Sstevel@tonic-gate int slen; 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate if (rp != NULL) 7157c478bd9Sstevel@tonic-gate ire_type = rp->ipRouteInfo.re_ire_type; 7167c478bd9Sstevel@tonic-gate else 7177c478bd9Sstevel@tonic-gate ire_type = rp6->ipv6RouteInfo.re_ire_type; 7187c478bd9Sstevel@tonic-gate if (ire_type != IRE_DEFAULT && 7197c478bd9Sstevel@tonic-gate ire_type != IRE_PREFIX && 7207c478bd9Sstevel@tonic-gate ire_type != IRE_HOST && 7217c478bd9Sstevel@tonic-gate ire_type != IRE_HOST_REDIRECT) 7227c478bd9Sstevel@tonic-gate return; 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate rtm = &m_rtmsg.m_rtm; 7257c478bd9Sstevel@tonic-gate (void) memset(rtm, 0, sizeof (m_rtmsg)); 7267c478bd9Sstevel@tonic-gate rtm->rtm_type = RTM_DELETE; 7277c478bd9Sstevel@tonic-gate rtm->rtm_seq = seqno; 7287c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_GATEWAY; 7297c478bd9Sstevel@tonic-gate rtm->rtm_version = RTM_VERSION; 7307c478bd9Sstevel@tonic-gate rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 7317c478bd9Sstevel@tonic-gate cp = m_rtmsg.m_space; 7327c478bd9Sstevel@tonic-gate if (rp != NULL) { 7337c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in); 7347c478bd9Sstevel@tonic-gate if (rp->ipRouteMask == IP_HOST_MASK) 7357c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_HOST; 7367c478bd9Sstevel@tonic-gate (void) memset(&sin, 0, slen); 7377c478bd9Sstevel@tonic-gate sin.sin_family = AF_INET; 7387c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteDest; 7397c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 7407c478bd9Sstevel@tonic-gate cp += slen; 7417c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteNextHop; 7427c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 7437c478bd9Sstevel@tonic-gate cp += slen; 7447c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteMask; 7457c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 7467c478bd9Sstevel@tonic-gate cp += slen; 7477c478bd9Sstevel@tonic-gate } else { 7487c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in6); 7497c478bd9Sstevel@tonic-gate if (rp6->ipv6RoutePfxLength == IPV6_ABITS) 7507c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_HOST; 7517c478bd9Sstevel@tonic-gate (void) memset(&sin6, 0, slen); 7527c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 7537c478bd9Sstevel@tonic-gate sin6.sin6_addr = rp6->ipv6RouteDest; 7547c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 7557c478bd9Sstevel@tonic-gate cp += slen; 7567c478bd9Sstevel@tonic-gate sin6.sin6_addr = rp6->ipv6RouteNextHop; 7577c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 7587c478bd9Sstevel@tonic-gate cp += slen; 7597c478bd9Sstevel@tonic-gate (void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr)); 7607c478bd9Sstevel@tonic-gate (void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS, 7617c478bd9Sstevel@tonic-gate (uchar_t *)&sin6.sin6_addr.s6_addr); 7627c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 7637c478bd9Sstevel@tonic-gate cp += slen; 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate rtm->rtm_msglen = cp - (char *)&m_rtmsg; 7667c478bd9Sstevel@tonic-gate if (debugonly) { 7677c478bd9Sstevel@tonic-gate /* 7687c478bd9Sstevel@tonic-gate * In debugonly mode, the routing socket message to delete the 7697c478bd9Sstevel@tonic-gate * current entry is not actually sent. However if verbose is 7707c478bd9Sstevel@tonic-gate * also set, the routing socket message that would have been 7717c478bd9Sstevel@tonic-gate * is printed. 7727c478bd9Sstevel@tonic-gate */ 7737c478bd9Sstevel@tonic-gate if (verbose) 7747c478bd9Sstevel@tonic-gate print_rtmsg(rtm, rtm->rtm_msglen); 7757c478bd9Sstevel@tonic-gate return; 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen); 7797c478bd9Sstevel@tonic-gate if (rlen < (int)rtm->rtm_msglen) { 7807c478bd9Sstevel@tonic-gate if (rlen < 0) { 7817c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7827c478bd9Sstevel@tonic-gate gettext("route: write to routing socket: %s\n"), 7837c478bd9Sstevel@tonic-gate strerror(errno)); 7847c478bd9Sstevel@tonic-gate } else { 7857c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: write to " 7867c478bd9Sstevel@tonic-gate "routing socket got only %d for rlen\n"), rlen); 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate return; 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate if (qflag) { 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate * In quiet mode, nothing is printed at all (unless the write() 7937c478bd9Sstevel@tonic-gate * itself failed. 7947c478bd9Sstevel@tonic-gate */ 7957c478bd9Sstevel@tonic-gate return; 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate if (verbose) { 7987c478bd9Sstevel@tonic-gate print_rtmsg(rtm, rlen); 7997c478bd9Sstevel@tonic-gate } else { 8007c478bd9Sstevel@tonic-gate struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate (void) printf("%-20.20s ", 8037c478bd9Sstevel@tonic-gate rtm->rtm_flags & RTF_HOST ? routename(sa) : 8047c478bd9Sstevel@tonic-gate netname(sa)); 8057c478bd9Sstevel@tonic-gate /* LINTED */ 8067c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)(salen(sa) + (char *)sa); 8077c478bd9Sstevel@tonic-gate (void) printf("%-20.20s ", routename(sa)); 8087c478bd9Sstevel@tonic-gate (void) printf("done\n"); 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate /* 8137c478bd9Sstevel@tonic-gate * Return the name of the host whose address is given. 8147c478bd9Sstevel@tonic-gate */ 8157c478bd9Sstevel@tonic-gate char * 8167c478bd9Sstevel@tonic-gate routename(struct sockaddr *sa) 8177c478bd9Sstevel@tonic-gate { 8187c478bd9Sstevel@tonic-gate char *cp; 8197c478bd9Sstevel@tonic-gate static char line[MAXHOSTNAMELEN + 1]; 8207c478bd9Sstevel@tonic-gate struct hostent *hp = NULL; 8217c478bd9Sstevel@tonic-gate static char domain[MAXHOSTNAMELEN + 1]; 8227c478bd9Sstevel@tonic-gate static boolean_t first = B_TRUE; 8237c478bd9Sstevel@tonic-gate struct in_addr in; 8247c478bd9Sstevel@tonic-gate struct in6_addr in6; 8257c478bd9Sstevel@tonic-gate int error_num; 8267c478bd9Sstevel@tonic-gate ushort_t *s; 8277c478bd9Sstevel@tonic-gate ushort_t *slim; 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate if (first) { 8307c478bd9Sstevel@tonic-gate first = B_FALSE; 8317c478bd9Sstevel@tonic-gate if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 8327c478bd9Sstevel@tonic-gate (cp = strchr(domain, '.'))) 8337c478bd9Sstevel@tonic-gate (void) strcpy(domain, cp + 1); 8347c478bd9Sstevel@tonic-gate else 8357c478bd9Sstevel@tonic-gate domain[0] = 0; 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate if (salen(sa) == 0) { 8397c478bd9Sstevel@tonic-gate (void) strcpy(line, "default"); 8407c478bd9Sstevel@tonic-gate return (line); 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate case AF_INET: 8457c478bd9Sstevel@tonic-gate /* LINTED */ 8467c478bd9Sstevel@tonic-gate in = ((struct sockaddr_in *)sa)->sin_addr; 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate cp = NULL; 8497c478bd9Sstevel@tonic-gate if (in.s_addr == INADDR_ANY) 8507c478bd9Sstevel@tonic-gate cp = "default"; 8517c478bd9Sstevel@tonic-gate if (cp == NULL && !nflag) { 8527c478bd9Sstevel@tonic-gate hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 8537c478bd9Sstevel@tonic-gate AF_INET); 8547c478bd9Sstevel@tonic-gate if (hp != NULL) { 8557c478bd9Sstevel@tonic-gate if (((cp = strchr(hp->h_name, '.')) != NULL) && 8567c478bd9Sstevel@tonic-gate (strcmp(cp + 1, domain) == 0)) 8577c478bd9Sstevel@tonic-gate *cp = 0; 8587c478bd9Sstevel@tonic-gate cp = hp->h_name; 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate if (cp != NULL) { 8627c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 8637c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 8647c478bd9Sstevel@tonic-gate } else { 8657c478bd9Sstevel@tonic-gate in.s_addr = ntohl(in.s_addr); 8667c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 8677c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8), 8687c478bd9Sstevel@tonic-gate C(in.s_addr)); 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate break; 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate case AF_LINK: 8737c478bd9Sstevel@tonic-gate return (link_ntoa((struct sockaddr_dl *)sa)); 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate case AF_INET6: 8767c478bd9Sstevel@tonic-gate /* LINTED */ 8777c478bd9Sstevel@tonic-gate in6 = ((struct sockaddr_in6 *)sa)->sin6_addr; 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate cp = NULL; 8807c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&in6)) 8817c478bd9Sstevel@tonic-gate cp = "default"; 8827c478bd9Sstevel@tonic-gate if (cp == NULL && !nflag) { 8837c478bd9Sstevel@tonic-gate hp = getipnodebyaddr((char *)&in6, 8847c478bd9Sstevel@tonic-gate sizeof (struct in6_addr), AF_INET6, &error_num); 8857c478bd9Sstevel@tonic-gate if (hp != NULL) { 8867c478bd9Sstevel@tonic-gate if (((cp = strchr(hp->h_name, '.')) != NULL) && 8877c478bd9Sstevel@tonic-gate (strcmp(cp + 1, domain) == 0)) 8887c478bd9Sstevel@tonic-gate *cp = 0; 8897c478bd9Sstevel@tonic-gate cp = hp->h_name; 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate if (cp != NULL) { 8937c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 8947c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 8957c478bd9Sstevel@tonic-gate } else { 8967c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&in6, line, 8977c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN); 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate if (hp != NULL) 9007c478bd9Sstevel@tonic-gate freehostent(hp); 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate break; 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate default: 9057c478bd9Sstevel@tonic-gate s = (ushort_t *)sa; 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate slim = s + ((salen(sa) + 1) >> 1); 9087c478bd9Sstevel@tonic-gate cp = line + sprintf(line, "(%d)", sa->sa_family); 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate while (++s < slim) /* start with sa->sa_data */ 9117c478bd9Sstevel@tonic-gate cp += sprintf(cp, " %x", *s); 9127c478bd9Sstevel@tonic-gate break; 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate return (line); 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate /* 9187c478bd9Sstevel@tonic-gate * Return the name of the network whose address is given. 9197c478bd9Sstevel@tonic-gate * The address is assumed to be that of a net or subnet, not a host. 9207c478bd9Sstevel@tonic-gate */ 9217c478bd9Sstevel@tonic-gate static char * 9227c478bd9Sstevel@tonic-gate netname(struct sockaddr *sa) 9237c478bd9Sstevel@tonic-gate { 9247c478bd9Sstevel@tonic-gate char *cp = NULL; 9257c478bd9Sstevel@tonic-gate static char line[MAXHOSTNAMELEN + 1]; 9267c478bd9Sstevel@tonic-gate struct netent *np; 9277c478bd9Sstevel@tonic-gate in_addr_t net, mask; 9287c478bd9Sstevel@tonic-gate int subnetshift; 9297c478bd9Sstevel@tonic-gate struct in_addr in; 9307c478bd9Sstevel@tonic-gate ushort_t *s; 9317c478bd9Sstevel@tonic-gate ushort_t *slim; 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate case AF_INET: 9367c478bd9Sstevel@tonic-gate /* LINTED */ 9377c478bd9Sstevel@tonic-gate in = ((struct sockaddr_in *)sa)->sin_addr; 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate in.s_addr = ntohl(in.s_addr); 9407c478bd9Sstevel@tonic-gate if (in.s_addr == INADDR_ANY) { 9417c478bd9Sstevel@tonic-gate cp = "default"; 9427c478bd9Sstevel@tonic-gate } else if (!nflag) { 9437c478bd9Sstevel@tonic-gate if (IN_CLASSA(in.s_addr)) { 9447c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 9457c478bd9Sstevel@tonic-gate subnetshift = 8; 9467c478bd9Sstevel@tonic-gate } else if (IN_CLASSB(in.s_addr)) { 9477c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 9487c478bd9Sstevel@tonic-gate subnetshift = 8; 9497c478bd9Sstevel@tonic-gate } else { 9507c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 9517c478bd9Sstevel@tonic-gate subnetshift = 4; 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate /* 9547c478bd9Sstevel@tonic-gate * If there are more bits than the standard mask 9557c478bd9Sstevel@tonic-gate * would suggest, subnets must be in use. 9567c478bd9Sstevel@tonic-gate * Guess at the subnet mask, assuming reasonable 9577c478bd9Sstevel@tonic-gate * width subnet fields. 9587c478bd9Sstevel@tonic-gate */ 9597c478bd9Sstevel@tonic-gate while (in.s_addr &~ mask) 9607c478bd9Sstevel@tonic-gate mask = (long)mask >> subnetshift; 9617c478bd9Sstevel@tonic-gate net = in.s_addr & mask; 9627c478bd9Sstevel@tonic-gate while ((mask & 1) == 0) 9637c478bd9Sstevel@tonic-gate mask >>= 1, net >>= 1; 9647c478bd9Sstevel@tonic-gate np = getnetbyaddr(net, AF_INET); 9657c478bd9Sstevel@tonic-gate if (np != NULL) 9667c478bd9Sstevel@tonic-gate cp = np->n_name; 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate if (cp != NULL) { 9697c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 9707c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 9717c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xffffff) == 0) { 9727c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u", C(in.s_addr >> 24)); 9737c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xffff) == 0) { 9747c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 9757c478bd9Sstevel@tonic-gate C(in.s_addr >> 16)); 9767c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xff) == 0) { 9777c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 9787c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8)); 9797c478bd9Sstevel@tonic-gate } else { 9807c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 9817c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8), 9827c478bd9Sstevel@tonic-gate C(in.s_addr)); 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate break; 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate case AF_LINK: 9877c478bd9Sstevel@tonic-gate return (link_ntoa((struct sockaddr_dl *)sa)); 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate case AF_INET6: 9907c478bd9Sstevel@tonic-gate return (routename(sa)); 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate default: 9937c478bd9Sstevel@tonic-gate /* LINTED */ 9947c478bd9Sstevel@tonic-gate s = (ushort_t *)sa->sa_data; 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate slim = s + ((salen(sa) + 1) >> 1); 9977c478bd9Sstevel@tonic-gate cp = line + sprintf(line, "af %d:", sa->sa_family); 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate while (s < slim) 10007c478bd9Sstevel@tonic-gate cp += sprintf(cp, " %x", *s++); 10017c478bd9Sstevel@tonic-gate break; 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate return (line); 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 1006*3f33f4f7Sjl138328 /* 1007*3f33f4f7Sjl138328 * Initialize a new structure. Keep in mind that ri_dst_str, ri_gate_str and 1008*3f33f4f7Sjl138328 * ri_ifp_str will be freed by det_rtcmd_irep, so they should either be NULL 1009*3f33f4f7Sjl138328 * or point to dynamically allocated memory. 1010*3f33f4f7Sjl138328 */ 1011*3f33f4f7Sjl138328 rtcmd_irep_t * 1012*3f33f4f7Sjl138328 new_rtcmd_irep(void) 1013*3f33f4f7Sjl138328 { 1014*3f33f4f7Sjl138328 rtcmd_irep_t *rcip; 1015*3f33f4f7Sjl138328 1016*3f33f4f7Sjl138328 rcip = calloc(1, sizeof (rtcmd_irep_t)); 1017*3f33f4f7Sjl138328 if (rcip == NULL) { 1018*3f33f4f7Sjl138328 quit("calloc", errno); 1019*3f33f4f7Sjl138328 } 1020*3f33f4f7Sjl138328 rcip->ri_af = AF_INET; 1021*3f33f4f7Sjl138328 rcip->ri_flags = RTF_STATIC; 1022*3f33f4f7Sjl138328 return (rcip); 1023*3f33f4f7Sjl138328 } 1024*3f33f4f7Sjl138328 10257c478bd9Sstevel@tonic-gate void 1026*3f33f4f7Sjl138328 del_rtcmd_irep(rtcmd_irep_t *rcip) 1027*3f33f4f7Sjl138328 { 1028*3f33f4f7Sjl138328 free(rcip->ri_dest_str); 1029*3f33f4f7Sjl138328 free(rcip->ri_gate_str); 1030*3f33f4f7Sjl138328 free(rcip->ri_ifp_str); 1031*3f33f4f7Sjl138328 if (rcip->ri_gate_hp != NULL) { 1032*3f33f4f7Sjl138328 freehostent(rcip->ri_gate_hp); 1033*3f33f4f7Sjl138328 } 1034*3f33f4f7Sjl138328 free(rcip); 1035*3f33f4f7Sjl138328 } 1036*3f33f4f7Sjl138328 1037*3f33f4f7Sjl138328 void 1038*3f33f4f7Sjl138328 save_string(char **dst, char *src) 1039*3f33f4f7Sjl138328 { 1040*3f33f4f7Sjl138328 free(*dst); 1041*3f33f4f7Sjl138328 *dst = strdup(src); 1042*3f33f4f7Sjl138328 if (*dst == NULL) { 1043*3f33f4f7Sjl138328 quit("malloc", errno); 1044*3f33f4f7Sjl138328 } 1045*3f33f4f7Sjl138328 } 1046*3f33f4f7Sjl138328 1047*3f33f4f7Sjl138328 /* 1048*3f33f4f7Sjl138328 * Print the short form summary of a route command. 1049*3f33f4f7Sjl138328 * Eg. "add net default: gateway 10.0.0.1" 1050*3f33f4f7Sjl138328 * The final newline is not added, allowing the caller to append additional 1051*3f33f4f7Sjl138328 * information. 1052*3f33f4f7Sjl138328 */ 1053*3f33f4f7Sjl138328 void 1054*3f33f4f7Sjl138328 print_rtcmd_short(FILE *to, rtcmd_irep_t *rcip, boolean_t gw_good, 1055*3f33f4f7Sjl138328 boolean_t to_saved) 1056*3f33f4f7Sjl138328 { 1057*3f33f4f7Sjl138328 char *cmd; 1058*3f33f4f7Sjl138328 char obuf[INET6_ADDRSTRLEN]; 1059*3f33f4f7Sjl138328 1060*3f33f4f7Sjl138328 switch (rcip->ri_cmd) { 1061*3f33f4f7Sjl138328 case RTM_ADD: 1062*3f33f4f7Sjl138328 cmd = "add"; 1063*3f33f4f7Sjl138328 break; 1064*3f33f4f7Sjl138328 case RTM_CHANGE: 1065*3f33f4f7Sjl138328 cmd = "change"; 1066*3f33f4f7Sjl138328 break; 1067*3f33f4f7Sjl138328 case RTM_DELETE: 1068*3f33f4f7Sjl138328 cmd = "delete"; 1069*3f33f4f7Sjl138328 break; 1070*3f33f4f7Sjl138328 case RTM_GET: 1071*3f33f4f7Sjl138328 cmd = "get"; 1072*3f33f4f7Sjl138328 break; 1073*3f33f4f7Sjl138328 default: 1074*3f33f4f7Sjl138328 assert(0); 1075*3f33f4f7Sjl138328 } 1076*3f33f4f7Sjl138328 1077*3f33f4f7Sjl138328 (void) fprintf(to, "%s%s %s %s", cmd, 1078*3f33f4f7Sjl138328 (to_saved) ? " persistent" : "", 1079*3f33f4f7Sjl138328 (rcip->ri_flags & RTF_HOST) ? "host" : "net", 1080*3f33f4f7Sjl138328 (rcip->ri_dest_str == NULL) ? "NULL" : rcip->ri_dest_str); 1081*3f33f4f7Sjl138328 1082*3f33f4f7Sjl138328 if (rcip->ri_gate_str != NULL) { 1083*3f33f4f7Sjl138328 switch (rcip->ri_af) { 1084*3f33f4f7Sjl138328 case AF_INET: 1085*3f33f4f7Sjl138328 if (nflag) { 1086*3f33f4f7Sjl138328 (void) fprintf(to, ": gateway %s", 1087*3f33f4f7Sjl138328 inet_ntoa(rcip->ri_gate.sin.sin_addr)); 1088*3f33f4f7Sjl138328 } else if (gw_good && 1089*3f33f4f7Sjl138328 rcip->ri_gate_hp != NULL && 1090*3f33f4f7Sjl138328 rcip->ri_gate_hp->h_addr_list[1] != NULL) { 1091*3f33f4f7Sjl138328 /* 1092*3f33f4f7Sjl138328 * Print the actual address used in the case 1093*3f33f4f7Sjl138328 * where there was more than one address 1094*3f33f4f7Sjl138328 * available for the name, and one was used 1095*3f33f4f7Sjl138328 * successfully. 1096*3f33f4f7Sjl138328 */ 1097*3f33f4f7Sjl138328 (void) fprintf(to, ": gateway %s (%s)", 1098*3f33f4f7Sjl138328 rcip->ri_gate_str, 1099*3f33f4f7Sjl138328 inet_ntoa(rcip->ri_gate.sin.sin_addr)); 1100*3f33f4f7Sjl138328 } else { 1101*3f33f4f7Sjl138328 (void) fprintf(to, ": gateway %s", 1102*3f33f4f7Sjl138328 rcip->ri_gate_str); 1103*3f33f4f7Sjl138328 } 1104*3f33f4f7Sjl138328 break; 1105*3f33f4f7Sjl138328 case AF_INET6: 1106*3f33f4f7Sjl138328 if (inet_ntop(AF_INET6, 1107*3f33f4f7Sjl138328 &rcip->ri_gate.sin6.sin6_addr, obuf, 1108*3f33f4f7Sjl138328 INET6_ADDRSTRLEN) != NULL) { 1109*3f33f4f7Sjl138328 if (nflag) { 1110*3f33f4f7Sjl138328 (void) fprintf(to, ": gateway %s", 1111*3f33f4f7Sjl138328 obuf); 1112*3f33f4f7Sjl138328 break; 1113*3f33f4f7Sjl138328 } 1114*3f33f4f7Sjl138328 if (gw_good && 1115*3f33f4f7Sjl138328 rcip->ri_gate_hp->h_addr_list[1] != NULL) { 1116*3f33f4f7Sjl138328 (void) fprintf(to, ": gateway %s (%s)", 1117*3f33f4f7Sjl138328 rcip->ri_gate_str, obuf); 1118*3f33f4f7Sjl138328 break; 1119*3f33f4f7Sjl138328 } 1120*3f33f4f7Sjl138328 } 1121*3f33f4f7Sjl138328 /* FALLTHROUGH */ 1122*3f33f4f7Sjl138328 default: 1123*3f33f4f7Sjl138328 (void) fprintf(to, ": gateway %s", 1124*3f33f4f7Sjl138328 rcip->ri_gate_str); 1125*3f33f4f7Sjl138328 break; 1126*3f33f4f7Sjl138328 } 1127*3f33f4f7Sjl138328 } 1128*3f33f4f7Sjl138328 } 1129*3f33f4f7Sjl138328 1130*3f33f4f7Sjl138328 void 1131*3f33f4f7Sjl138328 set_metric(rtcmd_irep_t *rcip, char *value, int key, boolean_t lock) 11327c478bd9Sstevel@tonic-gate { 11337c478bd9Sstevel@tonic-gate int flag = 0; 11347c478bd9Sstevel@tonic-gate uint_t noval, *valp = &noval; 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate switch (key) { 1137*3f33f4f7Sjl138328 #define caseof(x, y, z) \ 1138*3f33f4f7Sjl138328 case (x): valp = &(rcip->ri_metrics.z); flag = (y); break 1139*3f33f4f7Sjl138328 11407c478bd9Sstevel@tonic-gate caseof(K_MTU, RTV_MTU, rmx_mtu); 11417c478bd9Sstevel@tonic-gate caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 11427c478bd9Sstevel@tonic-gate caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 11437c478bd9Sstevel@tonic-gate caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 11447c478bd9Sstevel@tonic-gate caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 11457c478bd9Sstevel@tonic-gate caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 11467c478bd9Sstevel@tonic-gate caseof(K_RTT, RTV_RTT, rmx_rtt); 11477c478bd9Sstevel@tonic-gate caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 11487c478bd9Sstevel@tonic-gate #undef caseof 11497c478bd9Sstevel@tonic-gate } 1150*3f33f4f7Sjl138328 rcip->ri_inits |= flag; 1151*3f33f4f7Sjl138328 if (lock) 1152*3f33f4f7Sjl138328 rcip->ri_metrics.rmx_locks |= flag; 11537c478bd9Sstevel@tonic-gate *valp = atoi(value); 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate 1156*3f33f4f7Sjl138328 /* 1157*3f33f4f7Sjl138328 * Parse the options give in argv[], filling in rcip with the results. 1158*3f33f4f7Sjl138328 * If cmd_string is non-null, argc and argv are ignored, and cmd_string is 1159*3f33f4f7Sjl138328 * tokenized to produce the command line. Cmd_string is tokenized using 1160*3f33f4f7Sjl138328 * strtok, which will overwrite whitespace in the string with nulls. 1161*3f33f4f7Sjl138328 * 1162*3f33f4f7Sjl138328 * Returns B_TRUE on success and B_FALSE on failure. 1163*3f33f4f7Sjl138328 */ 1164*3f33f4f7Sjl138328 boolean_t 1165*3f33f4f7Sjl138328 args_to_rtcmd(rtcmd_irep_t *rcip, char **argv, char *cmd_string) 11667c478bd9Sstevel@tonic-gate { 1167*3f33f4f7Sjl138328 const char *ws = "\f\n\r\t\v "; 1168*3f33f4f7Sjl138328 char *tok = cmd_string; 1169*3f33f4f7Sjl138328 char *keyword_str; 1170*3f33f4f7Sjl138328 addr_type_t atype = ADDR_TYPE_ANY; 1171*3f33f4f7Sjl138328 boolean_t iflag = B_FALSE; 1172*3f33f4f7Sjl138328 boolean_t locknext = B_FALSE; 1173*3f33f4f7Sjl138328 boolean_t lockrest = B_FALSE; 1174*3f33f4f7Sjl138328 boolean_t dash_keyword; 11757c478bd9Sstevel@tonic-gate int key; 1176*3f33f4f7Sjl138328 char *err; 11777c478bd9Sstevel@tonic-gate 1178*3f33f4f7Sjl138328 if (cmd_string == NULL) { 1179*3f33f4f7Sjl138328 tok = argv[0]; 1180*3f33f4f7Sjl138328 } else { 1181*3f33f4f7Sjl138328 tok = strtok(cmd_string, ws); 11827c478bd9Sstevel@tonic-gate } 1183*3f33f4f7Sjl138328 1184*3f33f4f7Sjl138328 /* 1185*3f33f4f7Sjl138328 * The command keywords are already fully checked by main() or 1186*3f33f4f7Sjl138328 * search_rtfile(). 1187*3f33f4f7Sjl138328 */ 1188*3f33f4f7Sjl138328 switch (*tok) { 1189*3f33f4f7Sjl138328 case 'a': 1190*3f33f4f7Sjl138328 rcip->ri_cmd = RTM_ADD; 1191*3f33f4f7Sjl138328 break; 1192*3f33f4f7Sjl138328 case 'c': 1193*3f33f4f7Sjl138328 rcip->ri_cmd = RTM_CHANGE; 1194*3f33f4f7Sjl138328 break; 1195*3f33f4f7Sjl138328 case 'd': 1196*3f33f4f7Sjl138328 rcip->ri_cmd = RTM_DELETE; 1197*3f33f4f7Sjl138328 break; 1198*3f33f4f7Sjl138328 case 'g': 1199*3f33f4f7Sjl138328 rcip->ri_cmd = RTM_GET; 1200*3f33f4f7Sjl138328 break; 1201*3f33f4f7Sjl138328 default: 1202*3f33f4f7Sjl138328 /* NOTREACHED */ 1203*3f33f4f7Sjl138328 quit(gettext("Internal Error"), EINVAL); 1204*3f33f4f7Sjl138328 /* NOTREACHED */ 1205*3f33f4f7Sjl138328 } 1206*3f33f4f7Sjl138328 1207*3f33f4f7Sjl138328 #define NEXTTOKEN \ 1208*3f33f4f7Sjl138328 ((tok = (cmd_string == NULL ? *++argv : strtok(NULL, ws))) != NULL) 1209*3f33f4f7Sjl138328 1210*3f33f4f7Sjl138328 while (NEXTTOKEN) { 1211*3f33f4f7Sjl138328 keyword_str = tok; 1212*3f33f4f7Sjl138328 if (*tok == '-') { 1213*3f33f4f7Sjl138328 dash_keyword = B_TRUE; 1214*3f33f4f7Sjl138328 key = keyword(tok + 1); 1215*3f33f4f7Sjl138328 } else { 1216*3f33f4f7Sjl138328 dash_keyword = B_FALSE; 1217*3f33f4f7Sjl138328 key = keyword(tok); 1218*3f33f4f7Sjl138328 if (key != K_HOST && key != K_NET) { 1219*3f33f4f7Sjl138328 /* All others must be preceded by '-' */ 1220*3f33f4f7Sjl138328 key = 0; 1221*3f33f4f7Sjl138328 } 1222*3f33f4f7Sjl138328 } 1223*3f33f4f7Sjl138328 switch (key) { 1224*3f33f4f7Sjl138328 case K_HOST: 1225*3f33f4f7Sjl138328 if (atype == ADDR_TYPE_NET) { 1226*3f33f4f7Sjl138328 syntax_error(gettext("route: -host and -net " 1227*3f33f4f7Sjl138328 "are mutually exclusive\n")); 1228*3f33f4f7Sjl138328 return (B_FALSE); 1229*3f33f4f7Sjl138328 } 1230*3f33f4f7Sjl138328 atype = ADDR_TYPE_HOST; 1231*3f33f4f7Sjl138328 break; 1232*3f33f4f7Sjl138328 case K_NET: 1233*3f33f4f7Sjl138328 if (atype == ADDR_TYPE_HOST) { 1234*3f33f4f7Sjl138328 syntax_error(gettext("route: -host and -net " 1235*3f33f4f7Sjl138328 "are mutually exclusive\n")); 1236*3f33f4f7Sjl138328 return (B_FALSE); 1237*3f33f4f7Sjl138328 } 1238*3f33f4f7Sjl138328 atype = ADDR_TYPE_NET; 1239*3f33f4f7Sjl138328 break; 12407c478bd9Sstevel@tonic-gate case K_LINK: 1241*3f33f4f7Sjl138328 rcip->ri_af = AF_LINK; 12427c478bd9Sstevel@tonic-gate break; 12437c478bd9Sstevel@tonic-gate case K_INET: 1244*3f33f4f7Sjl138328 rcip->ri_af = AF_INET; 12457c478bd9Sstevel@tonic-gate break; 12467c478bd9Sstevel@tonic-gate case K_SA: 1247*3f33f4f7Sjl138328 rcip->ri_af = PF_ROUTE; 12487c478bd9Sstevel@tonic-gate break; 12497c478bd9Sstevel@tonic-gate case K_INET6: 1250*3f33f4f7Sjl138328 rcip->ri_af = AF_INET6; 12517c478bd9Sstevel@tonic-gate break; 12527c478bd9Sstevel@tonic-gate case K_IFACE: 12537c478bd9Sstevel@tonic-gate case K_INTERFACE: 12547c478bd9Sstevel@tonic-gate iflag = B_TRUE; 1255*3f33f4f7Sjl138328 break; 12567c478bd9Sstevel@tonic-gate case K_NOSTATIC: 1257*3f33f4f7Sjl138328 rcip->ri_flags &= ~RTF_STATIC; 12587c478bd9Sstevel@tonic-gate break; 12597c478bd9Sstevel@tonic-gate case K_LOCK: 1260*3f33f4f7Sjl138328 locknext = B_TRUE; 12617c478bd9Sstevel@tonic-gate break; 12627c478bd9Sstevel@tonic-gate case K_LOCKREST: 12637c478bd9Sstevel@tonic-gate lockrest = B_TRUE; 12647c478bd9Sstevel@tonic-gate break; 12657c478bd9Sstevel@tonic-gate case K_REJECT: 1266*3f33f4f7Sjl138328 rcip->ri_flags |= RTF_REJECT; 12677c478bd9Sstevel@tonic-gate break; 12687c478bd9Sstevel@tonic-gate case K_BLACKHOLE: 1269*3f33f4f7Sjl138328 rcip->ri_flags |= RTF_BLACKHOLE; 12707c478bd9Sstevel@tonic-gate break; 12717c478bd9Sstevel@tonic-gate case K_PROTO1: 1272*3f33f4f7Sjl138328 rcip->ri_flags |= RTF_PROTO1; 12737c478bd9Sstevel@tonic-gate break; 12747c478bd9Sstevel@tonic-gate case K_PROTO2: 1275*3f33f4f7Sjl138328 rcip->ri_flags |= RTF_PROTO2; 12767c478bd9Sstevel@tonic-gate break; 12777c478bd9Sstevel@tonic-gate case K_CLONING: 1278*3f33f4f7Sjl138328 rcip->ri_flags |= RTF_CLONING; 12797c478bd9Sstevel@tonic-gate break; 12807c478bd9Sstevel@tonic-gate case K_XRESOLVE: 1281*3f33f4f7Sjl138328 rcip->ri_flags |= RTF_XRESOLVE; 12827c478bd9Sstevel@tonic-gate break; 12837c478bd9Sstevel@tonic-gate case K_STATIC: 1284*3f33f4f7Sjl138328 rcip->ri_flags |= RTF_STATIC; 12857c478bd9Sstevel@tonic-gate break; 12867c478bd9Sstevel@tonic-gate case K_IFA: 1287*3f33f4f7Sjl138328 if (!NEXTTOKEN) { 1288*3f33f4f7Sjl138328 syntax_arg_missing(keyword_str); 1289*3f33f4f7Sjl138328 return (B_FALSE); 1290*3f33f4f7Sjl138328 } 1291*3f33f4f7Sjl138328 if (!getaddr(rcip, RTA_IFA, tok, atype)) { 1292*3f33f4f7Sjl138328 return (B_FALSE); 1293*3f33f4f7Sjl138328 } 12947c478bd9Sstevel@tonic-gate break; 12957c478bd9Sstevel@tonic-gate case K_IFP: 1296*3f33f4f7Sjl138328 if (!NEXTTOKEN) { 1297*3f33f4f7Sjl138328 syntax_arg_missing(keyword_str); 1298*3f33f4f7Sjl138328 return (B_FALSE); 1299*3f33f4f7Sjl138328 } 1300*3f33f4f7Sjl138328 if (!getaddr(rcip, RTA_IFP, tok, atype)) { 1301*3f33f4f7Sjl138328 return (B_FALSE); 1302*3f33f4f7Sjl138328 } 13037c478bd9Sstevel@tonic-gate break; 13047c478bd9Sstevel@tonic-gate case K_GATEWAY: 1305*3f33f4f7Sjl138328 if (!NEXTTOKEN) { 1306*3f33f4f7Sjl138328 syntax_arg_missing(keyword_str); 1307*3f33f4f7Sjl138328 return (B_FALSE); 1308*3f33f4f7Sjl138328 } 1309*3f33f4f7Sjl138328 if (!getaddr(rcip, RTA_GATEWAY, tok, atype)) { 1310*3f33f4f7Sjl138328 return (B_FALSE); 1311*3f33f4f7Sjl138328 } 13127c478bd9Sstevel@tonic-gate break; 13137c478bd9Sstevel@tonic-gate case K_DST: 1314*3f33f4f7Sjl138328 if (!NEXTTOKEN) { 1315*3f33f4f7Sjl138328 syntax_arg_missing(keyword_str); 1316*3f33f4f7Sjl138328 return (B_FALSE); 1317*3f33f4f7Sjl138328 } 1318*3f33f4f7Sjl138328 if (!getaddr(rcip, RTA_DST, tok, atype)) { 1319*3f33f4f7Sjl138328 return (B_FALSE); 1320*3f33f4f7Sjl138328 } 13217c478bd9Sstevel@tonic-gate break; 13227c478bd9Sstevel@tonic-gate case K_NETMASK: 1323*3f33f4f7Sjl138328 if (!NEXTTOKEN) { 1324*3f33f4f7Sjl138328 syntax_arg_missing(keyword_str); 1325*3f33f4f7Sjl138328 return (B_FALSE); 1326*3f33f4f7Sjl138328 } 1327*3f33f4f7Sjl138328 if (!getaddr(rcip, RTA_NETMASK, tok, atype)) { 1328*3f33f4f7Sjl138328 return (B_FALSE); 1329*3f33f4f7Sjl138328 } 1330*3f33f4f7Sjl138328 atype = ADDR_TYPE_NET; 13317c478bd9Sstevel@tonic-gate break; 13327c478bd9Sstevel@tonic-gate case K_MTU: 13337c478bd9Sstevel@tonic-gate case K_HOPCOUNT: 13347c478bd9Sstevel@tonic-gate case K_EXPIRE: 13357c478bd9Sstevel@tonic-gate case K_RECVPIPE: 13367c478bd9Sstevel@tonic-gate case K_SENDPIPE: 13377c478bd9Sstevel@tonic-gate case K_SSTHRESH: 13387c478bd9Sstevel@tonic-gate case K_RTT: 13397c478bd9Sstevel@tonic-gate case K_RTTVAR: 1340*3f33f4f7Sjl138328 if (!NEXTTOKEN) { 1341*3f33f4f7Sjl138328 syntax_arg_missing(keyword_str); 1342*3f33f4f7Sjl138328 return (B_FALSE); 1343*3f33f4f7Sjl138328 } 1344*3f33f4f7Sjl138328 set_metric(rcip, tok, key, locknext || lockrest); 1345*3f33f4f7Sjl138328 locknext = B_FALSE; 13467c478bd9Sstevel@tonic-gate break; 13477c478bd9Sstevel@tonic-gate case K_PRIVATE: 1348*3f33f4f7Sjl138328 rcip->ri_flags |= RTF_PRIVATE; 13497c478bd9Sstevel@tonic-gate break; 13507c478bd9Sstevel@tonic-gate case K_MULTIRT: 1351*3f33f4f7Sjl138328 rcip->ri_flags |= RTF_MULTIRT; 13527c478bd9Sstevel@tonic-gate break; 13537c478bd9Sstevel@tonic-gate case K_SETSRC: 1354*3f33f4f7Sjl138328 if (!NEXTTOKEN) { 1355*3f33f4f7Sjl138328 syntax_arg_missing(keyword_str); 1356*3f33f4f7Sjl138328 return (B_FALSE); 1357*3f33f4f7Sjl138328 } 1358*3f33f4f7Sjl138328 if (!getaddr(rcip, RTA_SRC, tok, atype)) { 1359*3f33f4f7Sjl138328 return (B_FALSE); 1360*3f33f4f7Sjl138328 } 1361*3f33f4f7Sjl138328 rcip->ri_flags |= RTF_SETSRC; 13627c478bd9Sstevel@tonic-gate break; 13637c478bd9Sstevel@tonic-gate default: 1364*3f33f4f7Sjl138328 if (dash_keyword) { 1365*3f33f4f7Sjl138328 syntax_bad_keyword(tok + 1); 1366*3f33f4f7Sjl138328 return (B_FALSE); 13677c478bd9Sstevel@tonic-gate } 1368*3f33f4f7Sjl138328 if ((rcip->ri_addrs & RTA_DST) == 0) { 1369*3f33f4f7Sjl138328 if (!getaddr(rcip, RTA_DST, tok, atype)) { 1370*3f33f4f7Sjl138328 return (B_FALSE); 1371*3f33f4f7Sjl138328 } 1372*3f33f4f7Sjl138328 } else if ((rcip->ri_addrs & RTA_GATEWAY) == 0) { 13737c478bd9Sstevel@tonic-gate /* 13747c478bd9Sstevel@tonic-gate * For the gateway parameter, retrieve the 13757c478bd9Sstevel@tonic-gate * pointer to the struct hostent so that all 13767c478bd9Sstevel@tonic-gate * possible addresses can be tried until one 13777c478bd9Sstevel@tonic-gate * is successful. 13787c478bd9Sstevel@tonic-gate */ 1379*3f33f4f7Sjl138328 if (!getaddr(rcip, RTA_GATEWAY, tok, atype)) { 1380*3f33f4f7Sjl138328 return (B_FALSE); 1381*3f33f4f7Sjl138328 } 13827c478bd9Sstevel@tonic-gate } else { 1383*3f33f4f7Sjl138328 ulong_t metric; 13847c478bd9Sstevel@tonic-gate /* 13857c478bd9Sstevel@tonic-gate * Assume that a regular number is a metric. 13867c478bd9Sstevel@tonic-gate * Needed for compatibility with old route 13877c478bd9Sstevel@tonic-gate * command syntax. 13887c478bd9Sstevel@tonic-gate */ 1389*3f33f4f7Sjl138328 errno = 0; 1390*3f33f4f7Sjl138328 metric = strtoul(tok, &err, 10); 1391*3f33f4f7Sjl138328 if (errno == 0 && *err == '\0' && 13927c478bd9Sstevel@tonic-gate metric < 0x80000000ul) { 13937c478bd9Sstevel@tonic-gate iflag = (metric == 0); 13947c478bd9Sstevel@tonic-gate if (verbose) { 13957c478bd9Sstevel@tonic-gate (void) printf("old usage of " 13967c478bd9Sstevel@tonic-gate "trailing number, assuming " 13977c478bd9Sstevel@tonic-gate "route %s\n", iflag ? 13987c478bd9Sstevel@tonic-gate "to if" : "via gateway"); 13997c478bd9Sstevel@tonic-gate } 14007c478bd9Sstevel@tonic-gate continue; 14017c478bd9Sstevel@tonic-gate } 1402*3f33f4f7Sjl138328 if (!getaddr(rcip, RTA_NETMASK, tok, atype)) { 1403*3f33f4f7Sjl138328 return (B_FALSE); 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate } 1407*3f33f4f7Sjl138328 } 1408*3f33f4f7Sjl138328 #undef NEXTTOKEN 1409*3f33f4f7Sjl138328 1410*3f33f4f7Sjl138328 if ((rcip->ri_addrs & RTA_DST) == 0) { 1411*3f33f4f7Sjl138328 syntax_error(gettext("route: destination required\n")); 1412*3f33f4f7Sjl138328 return (B_FALSE); 1413*3f33f4f7Sjl138328 } else if ((rcip->ri_cmd == RTM_ADD || rcip->ri_cmd == RTM_DELETE) && 1414*3f33f4f7Sjl138328 (rcip->ri_addrs & RTA_GATEWAY) == 0) { 1415*3f33f4f7Sjl138328 syntax_error(gettext( 1416*3f33f4f7Sjl138328 "route: gateway required for add or delete command\n")); 1417*3f33f4f7Sjl138328 return (B_FALSE); 1418*3f33f4f7Sjl138328 } 1419*3f33f4f7Sjl138328 1420*3f33f4f7Sjl138328 if (!iflag) { 1421*3f33f4f7Sjl138328 rcip->ri_flags |= RTF_GATEWAY; 1422*3f33f4f7Sjl138328 } 1423*3f33f4f7Sjl138328 1424*3f33f4f7Sjl138328 if (atype != ADDR_TYPE_NET && (rcip->ri_addrs & RTA_NETMASK)) { 1425*3f33f4f7Sjl138328 if ((rcip->ri_af == AF_INET && 1426*3f33f4f7Sjl138328 rcip->ri_mask.sin.sin_addr.s_addr == IP_HOST_MASK) || 1427*3f33f4f7Sjl138328 (rcip->ri_af == AF_INET6 && 1428*3f33f4f7Sjl138328 rcip->ri_masklen == IPV6_ABITS)) { 1429*3f33f4f7Sjl138328 atype = ADDR_TYPE_HOST; 1430*3f33f4f7Sjl138328 } else { 1431*3f33f4f7Sjl138328 atype = ADDR_TYPE_NET; 1432*3f33f4f7Sjl138328 } 1433*3f33f4f7Sjl138328 } 1434*3f33f4f7Sjl138328 if (atype == ADDR_TYPE_HOST) { 1435*3f33f4f7Sjl138328 rcip->ri_flags |= RTF_HOST; 1436*3f33f4f7Sjl138328 } 1437*3f33f4f7Sjl138328 return (B_TRUE); 14387c478bd9Sstevel@tonic-gate } 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate /* 1441*3f33f4f7Sjl138328 * This command always seeks to the end of the file prior to writing. 14427c478bd9Sstevel@tonic-gate */ 1443*3f33f4f7Sjl138328 void 1444*3f33f4f7Sjl138328 write_to_rtfile(FILE *fp, int argc, char **argv) 1445*3f33f4f7Sjl138328 { 1446*3f33f4f7Sjl138328 char file_line[BUF_SIZE]; 1447*3f33f4f7Sjl138328 int len; 1448*3f33f4f7Sjl138328 int i; 1449*3f33f4f7Sjl138328 1450*3f33f4f7Sjl138328 len = 0; 1451*3f33f4f7Sjl138328 for (i = 0; argc > 0 && len < BUF_SIZE; i++, argc--) { 1452*3f33f4f7Sjl138328 len += snprintf(&file_line[len], BUF_SIZE - len, "%s ", 1453*3f33f4f7Sjl138328 argv[i]); 14547c478bd9Sstevel@tonic-gate } 1455*3f33f4f7Sjl138328 if (len >= BUF_SIZE) 1456*3f33f4f7Sjl138328 quit(gettext("Internal Error"), EINVAL); 1457*3f33f4f7Sjl138328 file_line[len - 1] = '\n'; 1458*3f33f4f7Sjl138328 if (fseek(fp, 0, SEEK_END) != 0 || 1459*3f33f4f7Sjl138328 fputs(file_line, fp) == EOF) { 1460*3f33f4f7Sjl138328 quit(gettext("failed to write to route file"), 1461*3f33f4f7Sjl138328 errno); 1462*3f33f4f7Sjl138328 } 1463*3f33f4f7Sjl138328 } 1464*3f33f4f7Sjl138328 1465*3f33f4f7Sjl138328 boolean_t 1466*3f33f4f7Sjl138328 compare_rtcmd(rtcmd_irep_t *srch_rt, rtcmd_irep_t *file_rt) 1467*3f33f4f7Sjl138328 { 1468*3f33f4f7Sjl138328 if (strcmp(srch_rt->ri_dest_str, file_rt->ri_dest_str) != 0 || 1469*3f33f4f7Sjl138328 memcmp(&srch_rt->ri_mask, &file_rt->ri_mask, sizeof (su_t)) != 0) { 1470*3f33f4f7Sjl138328 return (B_FALSE); 1471*3f33f4f7Sjl138328 } 1472*3f33f4f7Sjl138328 return (srch_rt->ri_gate_str == NULL || 1473*3f33f4f7Sjl138328 strcmp(srch_rt->ri_gate_str, file_rt->ri_gate_str) == 0); 1474*3f33f4f7Sjl138328 } 1475*3f33f4f7Sjl138328 1476*3f33f4f7Sjl138328 /* 1477*3f33f4f7Sjl138328 * Search the route file for routes matching the supplied route. There are 3 1478*3f33f4f7Sjl138328 * modes of operation: 1479*3f33f4f7Sjl138328 * SEARCH_MODE_RET - no side effects. 1480*3f33f4f7Sjl138328 * SEARCH_MODE_PRINT - prints each matching line. 1481*3f33f4f7Sjl138328 * SEARCH_MODE_DEL - copies all valid, non-matching lines to tmp_fp. 1482*3f33f4f7Sjl138328 * 1483*3f33f4f7Sjl138328 * In all cases, the number of matches is returned. If rt is NULL, all routes 1484*3f33f4f7Sjl138328 * matching the global af value are considered matching. 1485*3f33f4f7Sjl138328 */ 1486*3f33f4f7Sjl138328 int 1487*3f33f4f7Sjl138328 search_rtfile(FILE *fp, FILE *temp_fp, rtcmd_irep_t *rt, search_mode_t mode) 1488*3f33f4f7Sjl138328 { 1489*3f33f4f7Sjl138328 char *tmp_buf; 1490*3f33f4f7Sjl138328 int match_cnt; 1491*3f33f4f7Sjl138328 boolean_t match; 1492*3f33f4f7Sjl138328 char file_line[BUF_SIZE + 4] = "add "; 1493*3f33f4f7Sjl138328 rtcmd_irep_t *thisrt; 1494*3f33f4f7Sjl138328 1495*3f33f4f7Sjl138328 match_cnt = 0; 1496*3f33f4f7Sjl138328 1497*3f33f4f7Sjl138328 /* 1498*3f33f4f7Sjl138328 * Leave space at the beginning of file_line for "add ". 1499*3f33f4f7Sjl138328 */ 1500*3f33f4f7Sjl138328 while (fgets(file_line + 4, BUF_SIZE, fp) != NULL) { 1501*3f33f4f7Sjl138328 1502*3f33f4f7Sjl138328 if (file_line[4] == '#' || file_line[4] == '\n') { 1503*3f33f4f7Sjl138328 /* Handle comments and blank lines */ 1504*3f33f4f7Sjl138328 if (mode == SEARCH_MODE_DEL && 1505*3f33f4f7Sjl138328 fputs(file_line + 4, temp_fp) == EOF) { 1506*3f33f4f7Sjl138328 quit(gettext( 1507*3f33f4f7Sjl138328 "route: failed to write to temp file"), 1508*3f33f4f7Sjl138328 errno); 1509*3f33f4f7Sjl138328 } 1510*3f33f4f7Sjl138328 continue; 1511*3f33f4f7Sjl138328 } 1512*3f33f4f7Sjl138328 thisrt = new_rtcmd_irep(); 1513*3f33f4f7Sjl138328 1514*3f33f4f7Sjl138328 exit_on_error = B_FALSE; 1515*3f33f4f7Sjl138328 tmp_buf = strdup(file_line); 1516*3f33f4f7Sjl138328 /* args_to_rtcmd() will mangle the string passed. */ 1517*3f33f4f7Sjl138328 if (!args_to_rtcmd(thisrt, NULL, tmp_buf)) { 1518*3f33f4f7Sjl138328 /* There was an error in args_to_rtcmd() or helpers */ 1519*3f33f4f7Sjl138328 del_rtcmd_irep(thisrt); 1520*3f33f4f7Sjl138328 free(tmp_buf); 1521*3f33f4f7Sjl138328 continue; 1522*3f33f4f7Sjl138328 } 1523*3f33f4f7Sjl138328 exit_on_error = B_TRUE; 1524*3f33f4f7Sjl138328 free(tmp_buf); 1525*3f33f4f7Sjl138328 1526*3f33f4f7Sjl138328 if (thisrt->ri_gate_str == NULL) { 1527*3f33f4f7Sjl138328 del_rtcmd_irep(thisrt); 1528*3f33f4f7Sjl138328 continue; 1529*3f33f4f7Sjl138328 } 1530*3f33f4f7Sjl138328 match = (rt == NULL) ? (thisrt->ri_af == af) : 1531*3f33f4f7Sjl138328 compare_rtcmd(rt, thisrt); 1532*3f33f4f7Sjl138328 1533*3f33f4f7Sjl138328 if (match) match_cnt++; 1534*3f33f4f7Sjl138328 if (match && mode == SEARCH_MODE_PRINT) { 1535*3f33f4f7Sjl138328 (void) printf("persistent: route %s", file_line); 1536*3f33f4f7Sjl138328 } 1537*3f33f4f7Sjl138328 if (match && mode == SEARCH_MODE_DEL) { 1538*3f33f4f7Sjl138328 thisrt->ri_cmd = RTM_DELETE; 1539*3f33f4f7Sjl138328 print_rtcmd_short(stdout, thisrt, B_FALSE, B_TRUE); 1540*3f33f4f7Sjl138328 (void) printf("\n"); 1541*3f33f4f7Sjl138328 } 1542*3f33f4f7Sjl138328 del_rtcmd_irep(thisrt); 1543*3f33f4f7Sjl138328 1544*3f33f4f7Sjl138328 if (!match && mode == SEARCH_MODE_DEL && 1545*3f33f4f7Sjl138328 fputs(file_line + 4, temp_fp) == EOF) { 1546*3f33f4f7Sjl138328 quit(gettext("failed to write to temp file"), 1547*3f33f4f7Sjl138328 errno); 1548*3f33f4f7Sjl138328 } 1549*3f33f4f7Sjl138328 } 1550*3f33f4f7Sjl138328 return (match_cnt); 1551*3f33f4f7Sjl138328 } 1552*3f33f4f7Sjl138328 1553*3f33f4f7Sjl138328 /* 1554*3f33f4f7Sjl138328 * Perform the route operation given in argv on the persistent route file. 1555*3f33f4f7Sjl138328 * If fflag is set, argc and argv are ignored, and the persisten route file 1556*3f33f4f7Sjl138328 * is flushed of all routes matching the global family. 1557*3f33f4f7Sjl138328 */ 1558*3f33f4f7Sjl138328 void 1559*3f33f4f7Sjl138328 save_route(int argc, char **argv) 1560*3f33f4f7Sjl138328 { 1561*3f33f4f7Sjl138328 rtcmd_irep_t *rt; 1562*3f33f4f7Sjl138328 int perm_fd; 1563*3f33f4f7Sjl138328 FILE *perm_fp; 1564*3f33f4f7Sjl138328 FILE *temp_fp; 1565*3f33f4f7Sjl138328 mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 1566*3f33f4f7Sjl138328 struct flock lock; 1567*3f33f4f7Sjl138328 struct stat st; 1568*3f33f4f7Sjl138328 const char commentstr[] = 1569*3f33f4f7Sjl138328 "# File generated by route(1M) - do not edit.\n"; 1570*3f33f4f7Sjl138328 1571*3f33f4f7Sjl138328 perm_fd = open(perm_file, O_RDWR | O_CREAT, fmode); 1572*3f33f4f7Sjl138328 if (perm_fd == -1 || fstat(perm_fd, &st) == -1) 1573*3f33f4f7Sjl138328 quit("failed to open route file", errno); 1574*3f33f4f7Sjl138328 1575*3f33f4f7Sjl138328 lock.l_type = F_WRLCK; 1576*3f33f4f7Sjl138328 lock.l_whence = SEEK_SET; 1577*3f33f4f7Sjl138328 lock.l_start = 0; 1578*3f33f4f7Sjl138328 lock.l_len = 0; 1579*3f33f4f7Sjl138328 if (fcntl(perm_fd, F_SETLK, &lock) != 0) { 1580*3f33f4f7Sjl138328 quit(gettext("failed to lock route file"), errno); 1581*3f33f4f7Sjl138328 /* NOTREACHED */ 1582*3f33f4f7Sjl138328 } 1583*3f33f4f7Sjl138328 if (st.st_size == 0 && 1584*3f33f4f7Sjl138328 write(perm_fd, commentstr, sizeof (commentstr) - 1) != 1585*3f33f4f7Sjl138328 sizeof (commentstr) - 1) 1586*3f33f4f7Sjl138328 quit(gettext("failed to open route file"), errno); 1587*3f33f4f7Sjl138328 1588*3f33f4f7Sjl138328 if ((perm_fp = fdopen(perm_fd, "r+")) == NULL) { 1589*3f33f4f7Sjl138328 quit(gettext("failed to open route file"), errno); 1590*3f33f4f7Sjl138328 /* NOTREACHED */ 1591*3f33f4f7Sjl138328 } 1592*3f33f4f7Sjl138328 1593*3f33f4f7Sjl138328 if (!fflag) { 1594*3f33f4f7Sjl138328 rt = new_rtcmd_irep(); 1595*3f33f4f7Sjl138328 (void) args_to_rtcmd(rt, argv, NULL); 1596*3f33f4f7Sjl138328 } 1597*3f33f4f7Sjl138328 if (fflag || rt->ri_cmd == RTM_DELETE) { 1598*3f33f4f7Sjl138328 if ((temp_fp = fopen(temp_file, "w")) == NULL) { 1599*3f33f4f7Sjl138328 quit(gettext("failed to open temp file"), errno); 1600*3f33f4f7Sjl138328 /* NOTREACHED */ 1601*3f33f4f7Sjl138328 } 1602*3f33f4f7Sjl138328 } 1603*3f33f4f7Sjl138328 if (fflag) { 1604*3f33f4f7Sjl138328 (void) search_rtfile(perm_fp, temp_fp, NULL, SEARCH_MODE_DEL); 1605*3f33f4f7Sjl138328 if (fclose(temp_fp) != 0 || rename(temp_file, perm_file) != 0) { 1606*3f33f4f7Sjl138328 quit(gettext("failed to update route file"), errno); 1607*3f33f4f7Sjl138328 /* NOTREACHED */ 1608*3f33f4f7Sjl138328 } 1609*3f33f4f7Sjl138328 (void) fclose(perm_fp); 1610*3f33f4f7Sjl138328 return; 1611*3f33f4f7Sjl138328 } 1612*3f33f4f7Sjl138328 1613*3f33f4f7Sjl138328 switch (rt->ri_cmd) { 1614*3f33f4f7Sjl138328 case RTM_ADD: 1615*3f33f4f7Sjl138328 if (search_rtfile(perm_fp, NULL, rt, SEARCH_MODE_NULL) > 0) { 1616*3f33f4f7Sjl138328 /* Route is already in the file */ 1617*3f33f4f7Sjl138328 print_rtcmd_short(stderr, rt, B_FALSE, B_TRUE); 1618*3f33f4f7Sjl138328 (void) fprintf(stderr, ": entry exists\n"); 1619*3f33f4f7Sjl138328 exit(1); 1620*3f33f4f7Sjl138328 } 1621*3f33f4f7Sjl138328 write_to_rtfile(perm_fp, argc - 1, argv + 1); 1622*3f33f4f7Sjl138328 print_rtcmd_short(stdout, rt, B_FALSE, B_TRUE); 1623*3f33f4f7Sjl138328 (void) printf("\n"); 1624*3f33f4f7Sjl138328 break; 1625*3f33f4f7Sjl138328 1626*3f33f4f7Sjl138328 case RTM_CHANGE: 1627*3f33f4f7Sjl138328 syntax_error( 1628*3f33f4f7Sjl138328 gettext("route: change command not supported with -p\n")); 1629*3f33f4f7Sjl138328 /* NOTREACHED */ 1630*3f33f4f7Sjl138328 1631*3f33f4f7Sjl138328 case RTM_DELETE: 1632*3f33f4f7Sjl138328 if (search_rtfile(perm_fp, temp_fp, rt, SEARCH_MODE_DEL) <= 0) { 1633*3f33f4f7Sjl138328 /* Route not found */ 1634*3f33f4f7Sjl138328 print_rtcmd_short(stderr, rt, B_FALSE, B_TRUE); 1635*3f33f4f7Sjl138328 (void) fprintf(stderr, gettext(": not in file\n")); 1636*3f33f4f7Sjl138328 exit(1); 1637*3f33f4f7Sjl138328 } 1638*3f33f4f7Sjl138328 if (fclose(temp_fp) != 0 || rename(temp_file, perm_file) != 0) { 1639*3f33f4f7Sjl138328 quit(gettext("failed to update route file"), errno); 1640*3f33f4f7Sjl138328 /* NOTREACHED */ 1641*3f33f4f7Sjl138328 } 1642*3f33f4f7Sjl138328 break; 1643*3f33f4f7Sjl138328 1644*3f33f4f7Sjl138328 case RTM_GET: 1645*3f33f4f7Sjl138328 if (search_rtfile(perm_fp, temp_fp, rt, SEARCH_MODE_PRINT) <= 1646*3f33f4f7Sjl138328 0) { 1647*3f33f4f7Sjl138328 print_rtcmd_short(stdout, rt, B_FALSE, B_TRUE); 1648*3f33f4f7Sjl138328 (void) printf(gettext(": not in file\n")); 1649*3f33f4f7Sjl138328 } 1650*3f33f4f7Sjl138328 break; 1651*3f33f4f7Sjl138328 1652*3f33f4f7Sjl138328 default: 1653*3f33f4f7Sjl138328 quit(gettext("Internal Error"), EINVAL); 1654*3f33f4f7Sjl138328 /* NOTREACHED */ 1655*3f33f4f7Sjl138328 } 1656*3f33f4f7Sjl138328 1657*3f33f4f7Sjl138328 /* 1658*3f33f4f7Sjl138328 * Closing the file unlocks it. 1659*3f33f4f7Sjl138328 */ 1660*3f33f4f7Sjl138328 (void) fclose(perm_fp); 1661*3f33f4f7Sjl138328 } 1662*3f33f4f7Sjl138328 1663*3f33f4f7Sjl138328 int 1664*3f33f4f7Sjl138328 show_saved_routes(int argc) 1665*3f33f4f7Sjl138328 { 1666*3f33f4f7Sjl138328 int perm_fd; 1667*3f33f4f7Sjl138328 FILE *perm_fp; 1668*3f33f4f7Sjl138328 struct flock lock; 1669*3f33f4f7Sjl138328 int count = 0; 1670*3f33f4f7Sjl138328 1671*3f33f4f7Sjl138328 if (argc != 1) { 1672*3f33f4f7Sjl138328 syntax_error(gettext("route: invalid arguments for show\n")); 1673*3f33f4f7Sjl138328 } 1674*3f33f4f7Sjl138328 1675*3f33f4f7Sjl138328 perm_fd = open(perm_file, O_RDONLY, 0); 1676*3f33f4f7Sjl138328 1677*3f33f4f7Sjl138328 if (perm_fd == -1) { 1678*3f33f4f7Sjl138328 if (errno == ENOENT) { 1679*3f33f4f7Sjl138328 (void) printf("No persistent routes are defined\n"); 1680*3f33f4f7Sjl138328 return (0); 1681*3f33f4f7Sjl138328 } else { 1682*3f33f4f7Sjl138328 quit(gettext("failed to open route file"), errno); 1683*3f33f4f7Sjl138328 } 1684*3f33f4f7Sjl138328 } 1685*3f33f4f7Sjl138328 lock.l_type = F_RDLCK; 1686*3f33f4f7Sjl138328 lock.l_whence = SEEK_SET; 1687*3f33f4f7Sjl138328 lock.l_start = 0; 1688*3f33f4f7Sjl138328 lock.l_len = 0; 1689*3f33f4f7Sjl138328 if (fcntl(perm_fd, F_SETLK, &lock) != 0) { 1690*3f33f4f7Sjl138328 quit(gettext("failed to lock route file"), 1691*3f33f4f7Sjl138328 errno); 1692*3f33f4f7Sjl138328 /* NOTREACHED */ 1693*3f33f4f7Sjl138328 } 1694*3f33f4f7Sjl138328 if ((perm_fp = fdopen(perm_fd, "r")) == NULL) { 1695*3f33f4f7Sjl138328 quit(gettext("failed to open route file"), errno); 1696*3f33f4f7Sjl138328 /* NOTREACHED */ 1697*3f33f4f7Sjl138328 } 1698*3f33f4f7Sjl138328 count += search_rtfile(perm_fp, NULL, NULL, SEARCH_MODE_PRINT); 1699*3f33f4f7Sjl138328 (void) fseek(perm_fp, 0, SEEK_SET); 1700*3f33f4f7Sjl138328 af = AF_INET6; 1701*3f33f4f7Sjl138328 count += search_rtfile(perm_fp, NULL, NULL, SEARCH_MODE_PRINT); 1702*3f33f4f7Sjl138328 1703*3f33f4f7Sjl138328 if (count == 0) 1704*3f33f4f7Sjl138328 (void) printf("No persistent routes are defined\n"); 1705*3f33f4f7Sjl138328 1706*3f33f4f7Sjl138328 (void) fclose(perm_fp); 1707*3f33f4f7Sjl138328 return (0); 1708*3f33f4f7Sjl138328 } 1709*3f33f4f7Sjl138328 1710*3f33f4f7Sjl138328 int 1711*3f33f4f7Sjl138328 newroute(char **argv) 1712*3f33f4f7Sjl138328 { 1713*3f33f4f7Sjl138328 rtcmd_irep_t *newrt; 1714*3f33f4f7Sjl138328 int ret, attempts, oerrno; 1715*3f33f4f7Sjl138328 char *err; 1716*3f33f4f7Sjl138328 char obuf[INET6_ADDRSTRLEN]; 1717*3f33f4f7Sjl138328 #define hp (newrt->ri_gate_hp) 1718*3f33f4f7Sjl138328 1719*3f33f4f7Sjl138328 newrt = new_rtcmd_irep(); 1720*3f33f4f7Sjl138328 (void) args_to_rtcmd(newrt, argv, NULL); 1721*3f33f4f7Sjl138328 1722*3f33f4f7Sjl138328 if (newrt->ri_cmd != RTM_GET && !tflag) { 1723*3f33f4f7Sjl138328 /* Don't want to read back our messages */ 1724*3f33f4f7Sjl138328 (void) shutdown(s, 0); 1725*3f33f4f7Sjl138328 } 1726*3f33f4f7Sjl138328 if (newrt->ri_addrs & RTA_IFP) { 1727*3f33f4f7Sjl138328 newrt->ri_ifp.sdl.sdl_index = if_nametoindex(newrt->ri_ifp_str); 1728*3f33f4f7Sjl138328 if (newrt->ri_ifp.sdl.sdl_index == 0) { 1729*3f33f4f7Sjl138328 if (errno != ENXIO) { 1730*3f33f4f7Sjl138328 quit("if_nametoindex", errno); 1731*3f33f4f7Sjl138328 } else { 1732*3f33f4f7Sjl138328 (void) fprintf(stderr, 1733*3f33f4f7Sjl138328 gettext("route: %s: no such interface\n"), 1734*3f33f4f7Sjl138328 newrt->ri_ifp_str); 1735*3f33f4f7Sjl138328 exit(1); 1736*3f33f4f7Sjl138328 } 1737*3f33f4f7Sjl138328 } 1738*3f33f4f7Sjl138328 newrt->ri_ifp.sdl.sdl_family = AF_LINK; 1739*3f33f4f7Sjl138328 } 17407c478bd9Sstevel@tonic-gate for (attempts = 1; ; attempts++) { 17417c478bd9Sstevel@tonic-gate errno = 0; 1742*3f33f4f7Sjl138328 if ((ret = rtmsg(newrt)) == 0) 17437c478bd9Sstevel@tonic-gate break; 17447c478bd9Sstevel@tonic-gate if (errno != ENETUNREACH && errno != ESRCH) 17457c478bd9Sstevel@tonic-gate break; 1746*3f33f4f7Sjl138328 if ((newrt->ri_addrs & RTA_GATEWAY) && hp != NULL && 17477c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts] != NULL) { 17487c478bd9Sstevel@tonic-gate switch (af) { 17497c478bd9Sstevel@tonic-gate case AF_INET: 1750*3f33f4f7Sjl138328 (void) memmove(&newrt->ri_gate.sin.sin_addr, 17517c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts], hp->h_length); 17527c478bd9Sstevel@tonic-gate continue; 17537c478bd9Sstevel@tonic-gate case AF_INET6: 1754*3f33f4f7Sjl138328 (void) memmove(&newrt->ri_gate.sin6.sin6_addr, 17557c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts], hp->h_length); 17567c478bd9Sstevel@tonic-gate continue; 17577c478bd9Sstevel@tonic-gate } 17587c478bd9Sstevel@tonic-gate } 17597c478bd9Sstevel@tonic-gate break; 17607c478bd9Sstevel@tonic-gate } 17617c478bd9Sstevel@tonic-gate oerrno = errno; 1762*3f33f4f7Sjl138328 1763*3f33f4f7Sjl138328 if (newrt->ri_cmd != RTM_GET) { 1764*3f33f4f7Sjl138328 print_rtcmd_short(stdout, newrt, (ret == 0), B_FALSE); 17657c478bd9Sstevel@tonic-gate if (ret == 0) 17667c478bd9Sstevel@tonic-gate (void) printf("\n"); 1767*3f33f4f7Sjl138328 } else if (ret != 0) { 1768*3f33f4f7Sjl138328 /* 1769*3f33f4f7Sjl138328 * Note: there is nothing additional to print for get 1770*3f33f4f7Sjl138328 * if ret == 0. 1771*3f33f4f7Sjl138328 */ 17727c478bd9Sstevel@tonic-gate if (nflag) { 1773*3f33f4f7Sjl138328 switch (newrt->ri_af) { 17747c478bd9Sstevel@tonic-gate case AF_INET: 17757c478bd9Sstevel@tonic-gate (void) printf(" %s", 1776*3f33f4f7Sjl138328 inet_ntoa(newrt->ri_dst.sin.sin_addr)); 17777c478bd9Sstevel@tonic-gate break; 17787c478bd9Sstevel@tonic-gate case AF_INET6: 17797c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, 1780*3f33f4f7Sjl138328 (void *)&newrt->ri_dst.sin6.sin6_addr, 17817c478bd9Sstevel@tonic-gate obuf, INET6_ADDRSTRLEN) != NULL) { 17827c478bd9Sstevel@tonic-gate (void) printf(" %s", obuf); 17837c478bd9Sstevel@tonic-gate break; 17847c478bd9Sstevel@tonic-gate } 17857c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 17867c478bd9Sstevel@tonic-gate default: 1787*3f33f4f7Sjl138328 (void) printf("%s", newrt->ri_dest_str); 17887c478bd9Sstevel@tonic-gate break; 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate } else { 1791*3f33f4f7Sjl138328 (void) printf("%s", newrt->ri_dest_str); 17927c478bd9Sstevel@tonic-gate } 17937c478bd9Sstevel@tonic-gate } 1794*3f33f4f7Sjl138328 1795*3f33f4f7Sjl138328 if (ret != 0) { 17967c478bd9Sstevel@tonic-gate switch (oerrno) { 17977c478bd9Sstevel@tonic-gate case ESRCH: 17987c478bd9Sstevel@tonic-gate err = "not in table"; 17997c478bd9Sstevel@tonic-gate break; 18007c478bd9Sstevel@tonic-gate case EBUSY: 18017c478bd9Sstevel@tonic-gate err = "entry in use"; 18027c478bd9Sstevel@tonic-gate break; 18037c478bd9Sstevel@tonic-gate case ENOBUFS: 18047c478bd9Sstevel@tonic-gate err = "routing table overflow"; 18057c478bd9Sstevel@tonic-gate break; 18067c478bd9Sstevel@tonic-gate case EEXIST: 18077c478bd9Sstevel@tonic-gate err = "entry exists"; 18087c478bd9Sstevel@tonic-gate break; 18097c478bd9Sstevel@tonic-gate case EPERM: 18107c478bd9Sstevel@tonic-gate err = "insufficient privileges"; 18117c478bd9Sstevel@tonic-gate break; 18127c478bd9Sstevel@tonic-gate default: 18137c478bd9Sstevel@tonic-gate err = strerror(oerrno); 18147c478bd9Sstevel@tonic-gate break; 18157c478bd9Sstevel@tonic-gate } 18167c478bd9Sstevel@tonic-gate (void) printf(": %s\n", err); 18177c478bd9Sstevel@tonic-gate } 1818*3f33f4f7Sjl138328 1819*3f33f4f7Sjl138328 del_rtcmd_irep(newrt); 18207c478bd9Sstevel@tonic-gate 18217c478bd9Sstevel@tonic-gate return (oerrno); 1822*3f33f4f7Sjl138328 #undef hp 18237c478bd9Sstevel@tonic-gate } 18247c478bd9Sstevel@tonic-gate 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate /* 18277c478bd9Sstevel@tonic-gate * Convert a network number to the corresponding IP address. 18287c478bd9Sstevel@tonic-gate * If the RTA_NETMASK hasn't been specified yet set it based 18297c478bd9Sstevel@tonic-gate * on the class of address. 18307c478bd9Sstevel@tonic-gate */ 18317c478bd9Sstevel@tonic-gate static void 1832*3f33f4f7Sjl138328 inet_makenetandmask(rtcmd_irep_t *rcip, in_addr_t net, struct sockaddr_in *sin) 18337c478bd9Sstevel@tonic-gate { 18347c478bd9Sstevel@tonic-gate in_addr_t addr, mask; 18357c478bd9Sstevel@tonic-gate 18367c478bd9Sstevel@tonic-gate if (net == 0) { 18377c478bd9Sstevel@tonic-gate mask = addr = 0; 18387c478bd9Sstevel@tonic-gate } else if (net < 128) { 18397c478bd9Sstevel@tonic-gate addr = net << IN_CLASSA_NSHIFT; 18407c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 18417c478bd9Sstevel@tonic-gate } else if (net < 65536) { 18427c478bd9Sstevel@tonic-gate addr = net << IN_CLASSB_NSHIFT; 18437c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 18447c478bd9Sstevel@tonic-gate } else if (net < 16777216L) { 18457c478bd9Sstevel@tonic-gate addr = net << IN_CLASSC_NSHIFT; 18467c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 18477c478bd9Sstevel@tonic-gate } else { 18487c478bd9Sstevel@tonic-gate addr = net; 18497c478bd9Sstevel@tonic-gate if ((addr & IN_CLASSA_HOST) == 0) 18507c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 18517c478bd9Sstevel@tonic-gate else if ((addr & IN_CLASSB_HOST) == 0) 18527c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 18537c478bd9Sstevel@tonic-gate else if ((addr & IN_CLASSC_HOST) == 0) 18547c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 18557c478bd9Sstevel@tonic-gate else { 18567c478bd9Sstevel@tonic-gate if (IN_CLASSA(addr)) 18577c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 18587c478bd9Sstevel@tonic-gate else if (IN_CLASSB(addr)) 18597c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 18607c478bd9Sstevel@tonic-gate else if (IN_CLASSC(addr)) 18617c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 18627c478bd9Sstevel@tonic-gate else 18637c478bd9Sstevel@tonic-gate mask = IP_HOST_MASK; 18647c478bd9Sstevel@tonic-gate mask = inet_makesubnetmask(addr, mask); 18657c478bd9Sstevel@tonic-gate } 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(addr); 18687c478bd9Sstevel@tonic-gate 1869*3f33f4f7Sjl138328 if (!(rcip->ri_addrs & RTA_NETMASK)) { 1870*3f33f4f7Sjl138328 rcip->ri_addrs |= RTA_NETMASK; 1871*3f33f4f7Sjl138328 sin = &rcip->ri_mask.sin; 18727c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(mask); 18737c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 18747c478bd9Sstevel@tonic-gate } 18757c478bd9Sstevel@tonic-gate } 18767c478bd9Sstevel@tonic-gate 18777c478bd9Sstevel@tonic-gate static in_addr_t 18787c478bd9Sstevel@tonic-gate inet_makesubnetmask(in_addr_t addr, in_addr_t mask) 18797c478bd9Sstevel@tonic-gate { 18807c478bd9Sstevel@tonic-gate int n; 18817c478bd9Sstevel@tonic-gate struct ifconf ifc; 18827c478bd9Sstevel@tonic-gate struct ifreq ifreq; 18837c478bd9Sstevel@tonic-gate struct ifreq *ifr; 18847c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 18857c478bd9Sstevel@tonic-gate char *buf; 18867c478bd9Sstevel@tonic-gate int numifs; 18877c478bd9Sstevel@tonic-gate size_t bufsize; 18887c478bd9Sstevel@tonic-gate int iosoc; 18897c478bd9Sstevel@tonic-gate in_addr_t if_addr, if_mask; 18907c478bd9Sstevel@tonic-gate in_addr_t if_subnetmask = 0; 18917c478bd9Sstevel@tonic-gate short if_flags; 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate if (mask == 0) 18947c478bd9Sstevel@tonic-gate return (0); 18957c478bd9Sstevel@tonic-gate if ((iosoc = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 18967c478bd9Sstevel@tonic-gate quit("socket", errno); 18977c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFNUM, (char *)&numifs) < 0) 18987c478bd9Sstevel@tonic-gate quit("ioctl", errno); 18997c478bd9Sstevel@tonic-gate bufsize = numifs * sizeof (struct ifreq); 19007c478bd9Sstevel@tonic-gate buf = malloc(bufsize); 19017c478bd9Sstevel@tonic-gate if (buf == NULL) 19027c478bd9Sstevel@tonic-gate quit("malloc", errno); 19037c478bd9Sstevel@tonic-gate (void) memset(&ifc, 0, sizeof (ifc)); 19047c478bd9Sstevel@tonic-gate ifc.ifc_len = bufsize; 19057c478bd9Sstevel@tonic-gate ifc.ifc_buf = buf; 19067c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFCONF, (char *)&ifc) < 0) 19077c478bd9Sstevel@tonic-gate quit("ioctl (get interface configuration)", errno); 19087c478bd9Sstevel@tonic-gate /* Let's check to see if this is maybe a local subnet route. */ 19097c478bd9Sstevel@tonic-gate ifr = ifc.ifc_req; 19107c478bd9Sstevel@tonic-gate for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { 19117c478bd9Sstevel@tonic-gate ifreq = *ifr; 19127c478bd9Sstevel@tonic-gate /* LINTED */ 19137c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr->ifr_addr; 19147c478bd9Sstevel@tonic-gate if_addr = ntohl(sin->sin_addr.s_addr); 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFFLAGS, (char *)&ifreq) < 0) 19177c478bd9Sstevel@tonic-gate quit("ioctl (get interface flags)", errno); 19187c478bd9Sstevel@tonic-gate if ((ifreq.ifr_flags & IFF_UP) == 0) 19197c478bd9Sstevel@tonic-gate continue; 19207c478bd9Sstevel@tonic-gate if_flags = ifreq.ifr_flags; 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFNETMASK, (char *)&ifreq) < 0) 19237c478bd9Sstevel@tonic-gate quit("ioctl (get netmask)", errno); 19247c478bd9Sstevel@tonic-gate /* LINTED */ 19257c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifreq.ifr_addr; 19267c478bd9Sstevel@tonic-gate if_mask = ntohl(sin->sin_addr.s_addr); 19277c478bd9Sstevel@tonic-gate if ((if_addr & mask) == (addr & mask)) { 19287c478bd9Sstevel@tonic-gate /* 19297c478bd9Sstevel@tonic-gate * Don't trust pt-pt interfaces if there are 19307c478bd9Sstevel@tonic-gate * other interfaces. 19317c478bd9Sstevel@tonic-gate */ 19327c478bd9Sstevel@tonic-gate if (if_flags & IFF_POINTOPOINT) { 19337c478bd9Sstevel@tonic-gate if_subnetmask = if_mask; 19347c478bd9Sstevel@tonic-gate continue; 19357c478bd9Sstevel@tonic-gate } 19367c478bd9Sstevel@tonic-gate /* 19377c478bd9Sstevel@tonic-gate * Fine. Just assume the same net mask as the 19387c478bd9Sstevel@tonic-gate * directly attached subnet interface is using. 19397c478bd9Sstevel@tonic-gate */ 19407c478bd9Sstevel@tonic-gate return (if_mask); 19417c478bd9Sstevel@tonic-gate } 19427c478bd9Sstevel@tonic-gate } 19437c478bd9Sstevel@tonic-gate if (if_subnetmask != 0) 19447c478bd9Sstevel@tonic-gate return (if_subnetmask); 19457c478bd9Sstevel@tonic-gate return (mask); 19467c478bd9Sstevel@tonic-gate } 19477c478bd9Sstevel@tonic-gate 19487c478bd9Sstevel@tonic-gate /* 1949*3f33f4f7Sjl138328 * Interpret an argument as a network address of some kind. 19507c478bd9Sstevel@tonic-gate * 19517c478bd9Sstevel@tonic-gate * If the address family is one looked up in getaddr() using one of the 19527c478bd9Sstevel@tonic-gate * getipnodebyX() functions (currently only AF_INET6), then callers should 19537c478bd9Sstevel@tonic-gate * freehostent() the returned "struct hostent" pointer if one was passed in. 1954*3f33f4f7Sjl138328 * 1955*3f33f4f7Sjl138328 * If exit_on_error is true, this function will cause route to exit on error by 1956*3f33f4f7Sjl138328 * calling syntax_error(). Otherwise, it returns B_TRUE on success or B_FALSE 1957*3f33f4f7Sjl138328 * on failure. 19587c478bd9Sstevel@tonic-gate */ 19597c478bd9Sstevel@tonic-gate static boolean_t 1960*3f33f4f7Sjl138328 getaddr(rtcmd_irep_t *rcip, int which, char *s, addr_type_t atype) 19617c478bd9Sstevel@tonic-gate { 1962*3f33f4f7Sjl138328 su_t *su; 1963*3f33f4f7Sjl138328 struct hostent **hpp; 19647c478bd9Sstevel@tonic-gate struct hostent *hp; 19657c478bd9Sstevel@tonic-gate boolean_t ret; 19667c478bd9Sstevel@tonic-gate 1967*3f33f4f7Sjl138328 if (which == RTA_GATEWAY) { 1968*3f33f4f7Sjl138328 hpp = &(rcip->ri_gate_hp); 1969*3f33f4f7Sjl138328 } else { 19707c478bd9Sstevel@tonic-gate hpp = &hp; 1971*3f33f4f7Sjl138328 } 19727c478bd9Sstevel@tonic-gate *hpp = NULL; 1973*3f33f4f7Sjl138328 1974*3f33f4f7Sjl138328 rcip->ri_addrs |= which; 19757c478bd9Sstevel@tonic-gate switch (which) { 19767c478bd9Sstevel@tonic-gate case RTA_DST: 1977*3f33f4f7Sjl138328 save_string(&rcip->ri_dest_str, s); 1978*3f33f4f7Sjl138328 su = &rcip->ri_dst; 1979*3f33f4f7Sjl138328 su->sa.sa_family = rcip->ri_af; 19807c478bd9Sstevel@tonic-gate break; 19817c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 1982*3f33f4f7Sjl138328 save_string(&rcip->ri_gate_str, s); 1983*3f33f4f7Sjl138328 su = &rcip->ri_gate; 1984*3f33f4f7Sjl138328 su->sa.sa_family = rcip->ri_af; 19857c478bd9Sstevel@tonic-gate break; 19867c478bd9Sstevel@tonic-gate case RTA_NETMASK: 1987*3f33f4f7Sjl138328 su = &rcip->ri_mask; 1988*3f33f4f7Sjl138328 su->sa.sa_family = rcip->ri_af; 19897c478bd9Sstevel@tonic-gate break; 19907c478bd9Sstevel@tonic-gate case RTA_IFP: 1991*3f33f4f7Sjl138328 save_string(&rcip->ri_ifp_str, s); 1992*3f33f4f7Sjl138328 return (B_TRUE); 19937c478bd9Sstevel@tonic-gate /* 19947c478bd9Sstevel@tonic-gate * RTA_SRC has overloaded meaning. It can represent the 19957c478bd9Sstevel@tonic-gate * src address of incoming or outgoing packets. 19967c478bd9Sstevel@tonic-gate */ 19977c478bd9Sstevel@tonic-gate case RTA_IFA: 1998*3f33f4f7Sjl138328 su = &rcip->ri_ifa; 1999*3f33f4f7Sjl138328 su->sa.sa_family = rcip->ri_af; 20007c478bd9Sstevel@tonic-gate break; 20017c478bd9Sstevel@tonic-gate case RTA_SRC: 2002*3f33f4f7Sjl138328 su = &rcip->ri_src; 2003*3f33f4f7Sjl138328 su->sa.sa_family = rcip->ri_af; 20047c478bd9Sstevel@tonic-gate break; 20057c478bd9Sstevel@tonic-gate default: 20067c478bd9Sstevel@tonic-gate /* NOTREACHED */ 20077c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 20087c478bd9Sstevel@tonic-gate /* NOTREACHED */ 20097c478bd9Sstevel@tonic-gate } 20107c478bd9Sstevel@tonic-gate if (strcmp(s, "default") == 0) { 20117c478bd9Sstevel@tonic-gate if (which == RTA_DST) { 2012*3f33f4f7Sjl138328 return (getaddr(rcip, RTA_NETMASK, s, ADDR_TYPE_NET)); 20137c478bd9Sstevel@tonic-gate } 20147c478bd9Sstevel@tonic-gate if (which == RTA_SRC) { 20157c478bd9Sstevel@tonic-gate return (B_TRUE); 20167c478bd9Sstevel@tonic-gate } 2017*3f33f4f7Sjl138328 return (B_TRUE); 20187c478bd9Sstevel@tonic-gate } 2019*3f33f4f7Sjl138328 switch (rcip->ri_af) { 20207c478bd9Sstevel@tonic-gate case AF_LINK: 20217c478bd9Sstevel@tonic-gate link_addr(s, &su->sdl); 20227c478bd9Sstevel@tonic-gate return (B_TRUE); 20237c478bd9Sstevel@tonic-gate case PF_ROUTE: 20247c478bd9Sstevel@tonic-gate sockaddr(s, &su->sa); 20257c478bd9Sstevel@tonic-gate return (B_TRUE); 20267c478bd9Sstevel@tonic-gate case AF_INET6: 20277c478bd9Sstevel@tonic-gate switch (which) { 20287c478bd9Sstevel@tonic-gate case RTA_DST: 20297c478bd9Sstevel@tonic-gate if (s[0] == '/') { 2030*3f33f4f7Sjl138328 syntax_error(gettext( 2031*3f33f4f7Sjl138328 "route: %s: unexpected '/'\n"), s); 2032*3f33f4f7Sjl138328 return (B_FALSE); 20337c478bd9Sstevel@tonic-gate } 2034*3f33f4f7Sjl138328 ret = in6_getaddr(s, &su->sin6, &rcip->ri_masklen, hpp); 2035*3f33f4f7Sjl138328 if (ret == B_FALSE) { 2036*3f33f4f7Sjl138328 return (B_FALSE); 2037*3f33f4f7Sjl138328 } 2038*3f33f4f7Sjl138328 switch (rcip->ri_masklen) { 20397c478bd9Sstevel@tonic-gate case NO_PREFIX: 20407c478bd9Sstevel@tonic-gate /* Nothing there - ok */ 2041*3f33f4f7Sjl138328 return (B_TRUE); 20427c478bd9Sstevel@tonic-gate case BAD_ADDR: 2043*3f33f4f7Sjl138328 syntax_error(gettext( 2044*3f33f4f7Sjl138328 "route: bad prefix length in %s\n"), s); 2045*3f33f4f7Sjl138328 return (B_FALSE); 20467c478bd9Sstevel@tonic-gate default: 2047*3f33f4f7Sjl138328 (void) memset(&rcip->ri_mask.sin6.sin6_addr, 0, 2048*3f33f4f7Sjl138328 sizeof (rcip->ri_mask.sin6.sin6_addr)); 2049*3f33f4f7Sjl138328 if (!in_prefixlentomask(rcip->ri_masklen, 2050*3f33f4f7Sjl138328 IPV6_ABITS, 2051*3f33f4f7Sjl138328 (uchar_t *)&rcip->ri_mask.sin6.sin6_addr)) { 2052*3f33f4f7Sjl138328 syntax_error(gettext( 2053*3f33f4f7Sjl138328 "route: bad prefix length: %d\n"), 2054*3f33f4f7Sjl138328 rcip->ri_masklen); 2055*3f33f4f7Sjl138328 return (B_FALSE); 20567c478bd9Sstevel@tonic-gate } 20577c478bd9Sstevel@tonic-gate break; 20587c478bd9Sstevel@tonic-gate } 2059*3f33f4f7Sjl138328 rcip->ri_mask.sin6.sin6_family = rcip->ri_af; 2060*3f33f4f7Sjl138328 rcip->ri_addrs |= RTA_NETMASK; 2061*3f33f4f7Sjl138328 return (B_TRUE); 20627c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 20637c478bd9Sstevel@tonic-gate case RTA_IFA: 20647c478bd9Sstevel@tonic-gate case RTA_SRC: 2065*3f33f4f7Sjl138328 return (in6_getaddr(s, &su->sin6, NULL, hpp)); 20667c478bd9Sstevel@tonic-gate case RTA_NETMASK: 2067*3f33f4f7Sjl138328 syntax_error( 20687c478bd9Sstevel@tonic-gate gettext("route: -netmask not supported for IPv6: " 2069*3f33f4f7Sjl138328 "use <prefix>/<prefix-length> instead\n")); 2070*3f33f4f7Sjl138328 return (B_FALSE); 20717c478bd9Sstevel@tonic-gate default: 20727c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 20737c478bd9Sstevel@tonic-gate /* NOTREACHED */ 20747c478bd9Sstevel@tonic-gate } 20757c478bd9Sstevel@tonic-gate case AF_INET: 20767c478bd9Sstevel@tonic-gate switch (which) { 20777c478bd9Sstevel@tonic-gate case RTA_DST: 20787c478bd9Sstevel@tonic-gate if (s[0] == '/') { 2079*3f33f4f7Sjl138328 syntax_error(gettext( 2080*3f33f4f7Sjl138328 "route: %s: unexpected '/'\n"), s); 2081*3f33f4f7Sjl138328 return (B_FALSE); 20827c478bd9Sstevel@tonic-gate } 2083*3f33f4f7Sjl138328 ret = in_getaddr(s, &su->sin, &rcip->ri_masklen, which, 2084*3f33f4f7Sjl138328 hpp, atype, rcip); 2085*3f33f4f7Sjl138328 if (ret == B_FALSE) { 2086*3f33f4f7Sjl138328 return (B_FALSE); 2087*3f33f4f7Sjl138328 } 2088*3f33f4f7Sjl138328 switch (rcip->ri_masklen) { 20897c478bd9Sstevel@tonic-gate case NO_PREFIX: 20907c478bd9Sstevel@tonic-gate /* Nothing there - ok */ 2091*3f33f4f7Sjl138328 return (B_TRUE); 20927c478bd9Sstevel@tonic-gate case BAD_ADDR: 2093*3f33f4f7Sjl138328 syntax_error(gettext( 2094*3f33f4f7Sjl138328 "route: bad prefix length in %s\n"), s); 2095*3f33f4f7Sjl138328 return (B_FALSE); 20967c478bd9Sstevel@tonic-gate default: 2097*3f33f4f7Sjl138328 (void) memset(&rcip->ri_mask.sin.sin_addr, 0, 2098*3f33f4f7Sjl138328 sizeof (rcip->ri_mask.sin.sin_addr)); 2099*3f33f4f7Sjl138328 if (!in_prefixlentomask(rcip->ri_masklen, 2100*3f33f4f7Sjl138328 IP_ABITS, 2101*3f33f4f7Sjl138328 (uchar_t *)&rcip->ri_mask.sin.sin_addr)) { 2102*3f33f4f7Sjl138328 syntax_error(gettext( 2103*3f33f4f7Sjl138328 "route: bad prefix length: %d\n"), 2104*3f33f4f7Sjl138328 rcip->ri_masklen); 2105*3f33f4f7Sjl138328 return (B_FALSE); 21067c478bd9Sstevel@tonic-gate } 21077c478bd9Sstevel@tonic-gate break; 21087c478bd9Sstevel@tonic-gate } 2109*3f33f4f7Sjl138328 rcip->ri_mask.sin.sin_family = rcip->ri_af; 2110*3f33f4f7Sjl138328 rcip->ri_addrs |= RTA_NETMASK; 2111*3f33f4f7Sjl138328 return (B_TRUE); 21127c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 21137c478bd9Sstevel@tonic-gate case RTA_IFA: 21147c478bd9Sstevel@tonic-gate case RTA_NETMASK: 21157c478bd9Sstevel@tonic-gate case RTA_SRC: 2116*3f33f4f7Sjl138328 return (in_getaddr(s, &su->sin, NULL, which, hpp, atype, 2117*3f33f4f7Sjl138328 rcip)); 21187c478bd9Sstevel@tonic-gate default: 21197c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 21207c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21217c478bd9Sstevel@tonic-gate } 21227c478bd9Sstevel@tonic-gate default: 21237c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 21247c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21257c478bd9Sstevel@tonic-gate } 2126*3f33f4f7Sjl138328 return (B_TRUE); 21277c478bd9Sstevel@tonic-gate } 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate /* 21307c478bd9Sstevel@tonic-gate * Interpret an argument as an IPv4 network address of some kind, 2131*3f33f4f7Sjl138328 * returning B_TRUE on success or B_FALSE on failure. 2132*3f33f4f7Sjl138328 * This function will cause an exit() on failure if exit_on_failure is set. 2133*3f33f4f7Sjl138328 * 21347c478bd9Sstevel@tonic-gate * Note that this *always* tries host interpretation before network 21357c478bd9Sstevel@tonic-gate * interpretation. 21367c478bd9Sstevel@tonic-gate * 21377c478bd9Sstevel@tonic-gate * If the plenp argument is non-NULL, allow <addr>/<n> syntax and 21387c478bd9Sstevel@tonic-gate * pass out <n> in *plenp. 21397c478bd9Sstevel@tonic-gate * If <n> doesn't parse return BAD_ADDR as *plenp. 21407c478bd9Sstevel@tonic-gate * If no /<n> is present return NO_PREFIX as *plenp. 21417c478bd9Sstevel@tonic-gate */ 21427c478bd9Sstevel@tonic-gate static boolean_t 21437c478bd9Sstevel@tonic-gate in_getaddr(char *s, struct sockaddr_in *sin, int *plenp, int which, 2144*3f33f4f7Sjl138328 struct hostent **hpp, addr_type_t atype, rtcmd_irep_t *rcip) 21457c478bd9Sstevel@tonic-gate { 21467c478bd9Sstevel@tonic-gate struct hostent *hp; 21477c478bd9Sstevel@tonic-gate struct netent *np; 21487c478bd9Sstevel@tonic-gate in_addr_t val; 21497c478bd9Sstevel@tonic-gate char str[BUFSIZ]; 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate (void) strncpy(str, s, sizeof (str)); 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate /* 21547c478bd9Sstevel@tonic-gate * Look for '/'<n> is plenp 21557c478bd9Sstevel@tonic-gate */ 21567c478bd9Sstevel@tonic-gate if (plenp != NULL) { 21577c478bd9Sstevel@tonic-gate char *cp; 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate *plenp = in_getprefixlen(str, IP_ABITS); 21607c478bd9Sstevel@tonic-gate if (*plenp == BAD_ADDR) 21617c478bd9Sstevel@tonic-gate return (B_FALSE); 21627c478bd9Sstevel@tonic-gate cp = strchr(str, '/'); 21637c478bd9Sstevel@tonic-gate if (cp != NULL) 21647c478bd9Sstevel@tonic-gate *cp = '\0'; 21657c478bd9Sstevel@tonic-gate } else if (strchr(str, '/') != NULL) { 2166*3f33f4f7Sjl138328 syntax_error(gettext("route: %s: unexpected '/'\n"), str); 2167*3f33f4f7Sjl138328 return (B_FALSE); 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate (void) memset(sin, 0, sizeof (*sin)); 21717c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate /* 21747c478bd9Sstevel@tonic-gate * Note: only the route destination can be a network, so we treat 21757c478bd9Sstevel@tonic-gate * all other addresses as though "-net" was not specified. 21767c478bd9Sstevel@tonic-gate */ 21777c478bd9Sstevel@tonic-gate if ((((val = inet_addr(str)) != (in_addr_t)-1) || 21787c478bd9Sstevel@tonic-gate strcmp(str, "255.255.255.255") == 0) && 2179*3f33f4f7Sjl138328 (which != RTA_DST || atype != ADDR_TYPE_NET)) { 21807c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = val; 21817c478bd9Sstevel@tonic-gate if (inet_lnaof(sin->sin_addr) != INADDR_ANY || 2182*3f33f4f7Sjl138328 atype == ADDR_TYPE_HOST) { 2183*3f33f4f7Sjl138328 if (rcip->ri_masklen == NO_PREFIX) { 2184*3f33f4f7Sjl138328 rcip->ri_masklen = 32; 2185*3f33f4f7Sjl138328 } 21867c478bd9Sstevel@tonic-gate return (B_TRUE); 2187*3f33f4f7Sjl138328 } 21887c478bd9Sstevel@tonic-gate val = ntohl(val); 21897c478bd9Sstevel@tonic-gate if (which == RTA_DST) 2190*3f33f4f7Sjl138328 inet_makenetandmask(rcip, val, sin); 2191*3f33f4f7Sjl138328 return (B_TRUE); 21927c478bd9Sstevel@tonic-gate } 2193*3f33f4f7Sjl138328 if (atype != ADDR_TYPE_HOST && (val = inet_network(str)) != 2194*3f33f4f7Sjl138328 (in_addr_t)-1) { 21957c478bd9Sstevel@tonic-gate if (which == RTA_DST) 2196*3f33f4f7Sjl138328 inet_makenetandmask(rcip, val, sin); 2197*3f33f4f7Sjl138328 return (B_TRUE); 21987c478bd9Sstevel@tonic-gate } 2199*3f33f4f7Sjl138328 if ((which != RTA_DST || atype != ADDR_TYPE_NET) && 22007c478bd9Sstevel@tonic-gate (hp = gethostbyname(str)) != NULL) { 22017c478bd9Sstevel@tonic-gate *hpp = hp; 22027c478bd9Sstevel@tonic-gate (void) memmove(&sin->sin_addr, hp->h_addr, 22037c478bd9Sstevel@tonic-gate hp->h_length); 2204*3f33f4f7Sjl138328 if (rcip->ri_masklen == NO_PREFIX) { 2205*3f33f4f7Sjl138328 rcip->ri_masklen = 32; 2206*3f33f4f7Sjl138328 } 22077c478bd9Sstevel@tonic-gate return (B_TRUE); 22087c478bd9Sstevel@tonic-gate } 2209*3f33f4f7Sjl138328 if (atype != ADDR_TYPE_HOST && (np = getnetbyname(str)) != NULL && 22107c478bd9Sstevel@tonic-gate (val = np->n_net) != 0) { 22117c478bd9Sstevel@tonic-gate if (which == RTA_DST) 2212*3f33f4f7Sjl138328 inet_makenetandmask(rcip, val, sin); 2213*3f33f4f7Sjl138328 return (B_TRUE); 22147c478bd9Sstevel@tonic-gate } 2215*3f33f4f7Sjl138328 syntax_error(gettext("%s: bad value\n"), s); 2216*3f33f4f7Sjl138328 return (B_FALSE); 22177c478bd9Sstevel@tonic-gate } 22187c478bd9Sstevel@tonic-gate 22197c478bd9Sstevel@tonic-gate /* 22207c478bd9Sstevel@tonic-gate * Interpret an argument as an IPv6 network address of some kind, 2221*3f33f4f7Sjl138328 * returning B_TRUE on success or B_FALSE on failure. 2222*3f33f4f7Sjl138328 * This function will cause an exit() on failure if exit_on_failure is set. 22237c478bd9Sstevel@tonic-gate * 22247c478bd9Sstevel@tonic-gate * If the last argument is non-NULL allow a <addr>/<n> syntax and 22257c478bd9Sstevel@tonic-gate * pass out <n> in *plenp. 22267c478bd9Sstevel@tonic-gate * If <n> doesn't parse return BAD_ADDR as *plenp. 22277c478bd9Sstevel@tonic-gate * If no /<n> is present return NO_PREFIX as *plenp. 22287c478bd9Sstevel@tonic-gate */ 22297c478bd9Sstevel@tonic-gate static boolean_t 22307c478bd9Sstevel@tonic-gate in6_getaddr(char *s, struct sockaddr_in6 *sin6, int *plenp, 22317c478bd9Sstevel@tonic-gate struct hostent **hpp) 22327c478bd9Sstevel@tonic-gate { 22337c478bd9Sstevel@tonic-gate struct hostent *hp; 22347c478bd9Sstevel@tonic-gate char str[BUFSIZ]; 22357c478bd9Sstevel@tonic-gate int error_num; 22367c478bd9Sstevel@tonic-gate 22377c478bd9Sstevel@tonic-gate (void) strncpy(str, s, sizeof (str)); 22387c478bd9Sstevel@tonic-gate 22397c478bd9Sstevel@tonic-gate /* 22407c478bd9Sstevel@tonic-gate * Look for '/'<n> is plenp 22417c478bd9Sstevel@tonic-gate */ 22427c478bd9Sstevel@tonic-gate if (plenp != NULL) { 22437c478bd9Sstevel@tonic-gate char *cp; 22447c478bd9Sstevel@tonic-gate 22457c478bd9Sstevel@tonic-gate *plenp = in_getprefixlen(str, IPV6_ABITS); 22467c478bd9Sstevel@tonic-gate if (*plenp == BAD_ADDR) 22477c478bd9Sstevel@tonic-gate return (B_FALSE); 22487c478bd9Sstevel@tonic-gate cp = strchr(str, '/'); 22497c478bd9Sstevel@tonic-gate if (cp != NULL) 22507c478bd9Sstevel@tonic-gate *cp = '\0'; 22517c478bd9Sstevel@tonic-gate } else if (strchr(str, '/') != NULL) { 2252*3f33f4f7Sjl138328 syntax_error(gettext("route: %s: unexpected '/'\n"), str); 2253*3f33f4f7Sjl138328 return (B_FALSE); 22547c478bd9Sstevel@tonic-gate } 22557c478bd9Sstevel@tonic-gate 22567c478bd9Sstevel@tonic-gate (void) memset(sin6, 0, sizeof (struct sockaddr_in6)); 22577c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 22587c478bd9Sstevel@tonic-gate 22597c478bd9Sstevel@tonic-gate hp = getipnodebyname(str, AF_INET6, 0, &error_num); 22607c478bd9Sstevel@tonic-gate if (hp != NULL) { 22617c478bd9Sstevel@tonic-gate *hpp = hp; 22627c478bd9Sstevel@tonic-gate (void) memmove(&sin6->sin6_addr, hp->h_addr, hp->h_length); 22637c478bd9Sstevel@tonic-gate return (B_TRUE); 22647c478bd9Sstevel@tonic-gate } 22657c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 2266*3f33f4f7Sjl138328 /* 2267*3f33f4f7Sjl138328 * This isn't a problem if we aren't going to use the address 2268*3f33f4f7Sjl138328 * right away. 2269*3f33f4f7Sjl138328 */ 2270*3f33f4f7Sjl138328 if (!exit_on_error) { 2271*3f33f4f7Sjl138328 return (B_TRUE); 22727c478bd9Sstevel@tonic-gate } 2273*3f33f4f7Sjl138328 syntax_error(gettext("route: %s: bad address (try " 2274*3f33f4f7Sjl138328 "again later)\n"), s); 2275*3f33f4f7Sjl138328 return (B_FALSE); 2276*3f33f4f7Sjl138328 } 2277*3f33f4f7Sjl138328 syntax_error(gettext("route: %s: bad address\n"), s); 2278*3f33f4f7Sjl138328 return (B_FALSE); 22797c478bd9Sstevel@tonic-gate } 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate /* 22827c478bd9Sstevel@tonic-gate * If "slash" is zero this parses the whole string as 22837c478bd9Sstevel@tonic-gate * an integer. With "slash" non zero it parses the tail part as an integer. 22847c478bd9Sstevel@tonic-gate * 22857c478bd9Sstevel@tonic-gate * If it is not a valid integer this returns BAD_ADDR. 22867c478bd9Sstevel@tonic-gate * If there is /<n> present this returns NO_PREFIX. 22877c478bd9Sstevel@tonic-gate */ 22887c478bd9Sstevel@tonic-gate int 22897c478bd9Sstevel@tonic-gate in_getprefixlen(char *addr, int max_plen) 22907c478bd9Sstevel@tonic-gate { 22917c478bd9Sstevel@tonic-gate int prefixlen; 22927c478bd9Sstevel@tonic-gate char *str, *end; 22937c478bd9Sstevel@tonic-gate 22947c478bd9Sstevel@tonic-gate str = strchr(addr, '/'); 22957c478bd9Sstevel@tonic-gate if (str == NULL) 22967c478bd9Sstevel@tonic-gate return (NO_PREFIX); 22977c478bd9Sstevel@tonic-gate str++; 22987c478bd9Sstevel@tonic-gate 22997c478bd9Sstevel@tonic-gate prefixlen = strtol(str, &end, 10); 23007c478bd9Sstevel@tonic-gate if (prefixlen < 0) 23017c478bd9Sstevel@tonic-gate return (BAD_ADDR); 23027c478bd9Sstevel@tonic-gate if (str == end) 23037c478bd9Sstevel@tonic-gate return (BAD_ADDR); 23047c478bd9Sstevel@tonic-gate if (max_plen != 0 && max_plen < prefixlen) 23057c478bd9Sstevel@tonic-gate return (BAD_ADDR); 23067c478bd9Sstevel@tonic-gate else 23077c478bd9Sstevel@tonic-gate return (prefixlen); 23087c478bd9Sstevel@tonic-gate } 23097c478bd9Sstevel@tonic-gate 23107c478bd9Sstevel@tonic-gate /* 23117c478bd9Sstevel@tonic-gate * Convert a prefix length to a mask. 23127c478bd9Sstevel@tonic-gate * Returns B_TRUE if ok. B_FALSE otherwise. 23137c478bd9Sstevel@tonic-gate * Assumes the mask array is zeroed by the caller. 23147c478bd9Sstevel@tonic-gate */ 23157c478bd9Sstevel@tonic-gate boolean_t 23167c478bd9Sstevel@tonic-gate in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 23177c478bd9Sstevel@tonic-gate { 23187c478bd9Sstevel@tonic-gate if (prefixlen < 0 || prefixlen > maxlen) 23197c478bd9Sstevel@tonic-gate return (B_FALSE); 23207c478bd9Sstevel@tonic-gate 23217c478bd9Sstevel@tonic-gate while (prefixlen > 0) { 23227c478bd9Sstevel@tonic-gate if (prefixlen >= 8) { 23237c478bd9Sstevel@tonic-gate *mask++ = 0xFF; 23247c478bd9Sstevel@tonic-gate prefixlen -= 8; 23257c478bd9Sstevel@tonic-gate continue; 23267c478bd9Sstevel@tonic-gate } 23277c478bd9Sstevel@tonic-gate *mask |= 1 << (8 - prefixlen); 23287c478bd9Sstevel@tonic-gate prefixlen--; 23297c478bd9Sstevel@tonic-gate } 23307c478bd9Sstevel@tonic-gate return (B_TRUE); 23317c478bd9Sstevel@tonic-gate } 23327c478bd9Sstevel@tonic-gate 23337c478bd9Sstevel@tonic-gate void 23347c478bd9Sstevel@tonic-gate rtmonitor(int argc, char *argv[]) 23357c478bd9Sstevel@tonic-gate { 23367c478bd9Sstevel@tonic-gate int n; 23377c478bd9Sstevel@tonic-gate intmax_t msg[2048 / sizeof (intmax_t)]; 23387c478bd9Sstevel@tonic-gate 23397c478bd9Sstevel@tonic-gate if (tflag) 23407c478bd9Sstevel@tonic-gate exit(0); 23417c478bd9Sstevel@tonic-gate verbose = B_TRUE; 23427c478bd9Sstevel@tonic-gate if (argc > 1) { 23437c478bd9Sstevel@tonic-gate argv++; 23447c478bd9Sstevel@tonic-gate if (argc == 2 && **argv == '-') { 23457c478bd9Sstevel@tonic-gate switch (keyword(*argv + 1)) { 23467c478bd9Sstevel@tonic-gate case K_INET: 23477c478bd9Sstevel@tonic-gate af = AF_INET; 23487c478bd9Sstevel@tonic-gate break; 23497c478bd9Sstevel@tonic-gate case K_LINK: 23507c478bd9Sstevel@tonic-gate af = AF_LINK; 23517c478bd9Sstevel@tonic-gate break; 23527c478bd9Sstevel@tonic-gate case K_INET6: 23537c478bd9Sstevel@tonic-gate af = AF_INET6; 23547c478bd9Sstevel@tonic-gate break; 23557c478bd9Sstevel@tonic-gate default: 23567c478bd9Sstevel@tonic-gate usage(*argv); 23577c478bd9Sstevel@tonic-gate /* NOTREACHED */ 23587c478bd9Sstevel@tonic-gate } 23597c478bd9Sstevel@tonic-gate } else { 23607c478bd9Sstevel@tonic-gate usage(*argv); 23617c478bd9Sstevel@tonic-gate } 23627c478bd9Sstevel@tonic-gate (void) close(s); 23637c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, af); 23647c478bd9Sstevel@tonic-gate if (s < 0) 23657c478bd9Sstevel@tonic-gate quit("socket", errno); 23667c478bd9Sstevel@tonic-gate } 23677c478bd9Sstevel@tonic-gate for (;;) { 23687c478bd9Sstevel@tonic-gate n = read(s, msg, sizeof (msg)); 23697c478bd9Sstevel@tonic-gate if (n <= 0) 23707c478bd9Sstevel@tonic-gate quit("read", errno); 23717c478bd9Sstevel@tonic-gate (void) printf("got message of size %d\n", n); 23727c478bd9Sstevel@tonic-gate print_rtmsg((struct rt_msghdr *)msg, n); 23737c478bd9Sstevel@tonic-gate } 23747c478bd9Sstevel@tonic-gate } 23757c478bd9Sstevel@tonic-gate 23767c478bd9Sstevel@tonic-gate int 2377*3f33f4f7Sjl138328 rtmsg(rtcmd_irep_t *newrt) 23787c478bd9Sstevel@tonic-gate { 23797c478bd9Sstevel@tonic-gate static int seq; 23807c478bd9Sstevel@tonic-gate int rlen; 23817c478bd9Sstevel@tonic-gate char *cp = m_rtmsg.m_space; 23827c478bd9Sstevel@tonic-gate int l; 23837c478bd9Sstevel@tonic-gate 23847c478bd9Sstevel@tonic-gate errno = 0; 23857c478bd9Sstevel@tonic-gate (void) memset(&m_rtmsg, 0, sizeof (m_rtmsg)); 2386*3f33f4f7Sjl138328 2387*3f33f4f7Sjl138328 if (newrt->ri_cmd == RTM_GET) { 2388*3f33f4f7Sjl138328 newrt->ri_ifp.sa.sa_family = AF_LINK; 2389*3f33f4f7Sjl138328 newrt->ri_addrs |= RTA_IFP; 23907c478bd9Sstevel@tonic-gate } 2391*3f33f4f7Sjl138328 23927c478bd9Sstevel@tonic-gate #define rtm m_rtmsg.m_rtm 2393*3f33f4f7Sjl138328 rtm.rtm_type = newrt->ri_cmd; 2394*3f33f4f7Sjl138328 rtm.rtm_flags = newrt->ri_flags; 23957c478bd9Sstevel@tonic-gate rtm.rtm_version = RTM_VERSION; 23967c478bd9Sstevel@tonic-gate rtm.rtm_seq = ++seq; 2397*3f33f4f7Sjl138328 rtm.rtm_addrs = newrt->ri_addrs; 2398*3f33f4f7Sjl138328 rtm.rtm_rmx = newrt->ri_metrics; 2399*3f33f4f7Sjl138328 rtm.rtm_inits = newrt->ri_inits; 24007c478bd9Sstevel@tonic-gate 24017c478bd9Sstevel@tonic-gate #define NEXTADDR(w, u) \ 2402*3f33f4f7Sjl138328 if (newrt->ri_addrs & (w)) { \ 24037c478bd9Sstevel@tonic-gate l = ROUNDUP_LONG(salen(&u.sa)); \ 24047c478bd9Sstevel@tonic-gate (void) memmove(cp, &(u), l); \ 24057c478bd9Sstevel@tonic-gate cp += l; \ 24067c478bd9Sstevel@tonic-gate if (verbose) \ 24077c478bd9Sstevel@tonic-gate sodump(&(u), #u); \ 24087c478bd9Sstevel@tonic-gate } 2409*3f33f4f7Sjl138328 NEXTADDR(RTA_DST, newrt->ri_dst); 2410*3f33f4f7Sjl138328 NEXTADDR(RTA_GATEWAY, newrt->ri_gate); 2411*3f33f4f7Sjl138328 NEXTADDR(RTA_NETMASK, newrt->ri_mask); 2412*3f33f4f7Sjl138328 NEXTADDR(RTA_IFP, newrt->ri_ifp); 2413*3f33f4f7Sjl138328 NEXTADDR(RTA_IFA, newrt->ri_ifa); 24147c478bd9Sstevel@tonic-gate /* 24157c478bd9Sstevel@tonic-gate * RTA_SRC has overloaded meaning. It can represent the 24167c478bd9Sstevel@tonic-gate * src address of incoming or outgoing packets. 24177c478bd9Sstevel@tonic-gate */ 2418*3f33f4f7Sjl138328 NEXTADDR(RTA_SRC, newrt->ri_src); 24197c478bd9Sstevel@tonic-gate #undef NEXTADDR 24207c478bd9Sstevel@tonic-gate rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 24217c478bd9Sstevel@tonic-gate if (verbose) 24227c478bd9Sstevel@tonic-gate print_rtmsg(&rtm, l); 24237c478bd9Sstevel@tonic-gate if (debugonly) 24247c478bd9Sstevel@tonic-gate return (0); 24257c478bd9Sstevel@tonic-gate if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 24267c478bd9Sstevel@tonic-gate switch (errno) { 24277c478bd9Sstevel@tonic-gate case ESRCH: 24287c478bd9Sstevel@tonic-gate case EBUSY: 24297c478bd9Sstevel@tonic-gate case ENOBUFS: 24307c478bd9Sstevel@tonic-gate case EEXIST: 24317c478bd9Sstevel@tonic-gate case ENETUNREACH: 24327c478bd9Sstevel@tonic-gate case EHOSTUNREACH: 24337c478bd9Sstevel@tonic-gate case EPERM: 24347c478bd9Sstevel@tonic-gate break; 24357c478bd9Sstevel@tonic-gate default: 24367c478bd9Sstevel@tonic-gate perror(gettext("writing to routing socket")); 24377c478bd9Sstevel@tonic-gate break; 24387c478bd9Sstevel@tonic-gate } 24397c478bd9Sstevel@tonic-gate return (-1); 24407c478bd9Sstevel@tonic-gate } else if (rlen < (int)rtm.rtm_msglen) { 24417c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 24427c478bd9Sstevel@tonic-gate gettext("route: write to routing socket got only %d for " 24437c478bd9Sstevel@tonic-gate "len\n"), rlen); 24447c478bd9Sstevel@tonic-gate return (-1); 24457c478bd9Sstevel@tonic-gate } 2446*3f33f4f7Sjl138328 if (newrt->ri_cmd == RTM_GET) { 24477c478bd9Sstevel@tonic-gate do { 24487c478bd9Sstevel@tonic-gate l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg)); 24497c478bd9Sstevel@tonic-gate } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 24507c478bd9Sstevel@tonic-gate if (l < 0) { 24517c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 24527c478bd9Sstevel@tonic-gate gettext("route: read from routing socket: %s\n"), 24537c478bd9Sstevel@tonic-gate strerror(errno)); 24547c478bd9Sstevel@tonic-gate } else { 2455*3f33f4f7Sjl138328 print_getmsg(newrt, &rtm, l); 24567c478bd9Sstevel@tonic-gate } 24577c478bd9Sstevel@tonic-gate } 24587c478bd9Sstevel@tonic-gate #undef rtm 24597c478bd9Sstevel@tonic-gate return (0); 24607c478bd9Sstevel@tonic-gate } 24617c478bd9Sstevel@tonic-gate 24627c478bd9Sstevel@tonic-gate static char *msgtypes[] = { 24637c478bd9Sstevel@tonic-gate "", 24647c478bd9Sstevel@tonic-gate "RTM_ADD: Add Route", 24657c478bd9Sstevel@tonic-gate "RTM_DELETE: Delete Route", 24667c478bd9Sstevel@tonic-gate "RTM_CHANGE: Change Metrics or flags", 24677c478bd9Sstevel@tonic-gate "RTM_GET: Report Metrics", 24687c478bd9Sstevel@tonic-gate "RTM_LOSING: Kernel Suspects Partitioning", 24697c478bd9Sstevel@tonic-gate "RTM_REDIRECT: Told to use different route", 24707c478bd9Sstevel@tonic-gate "RTM_MISS: Lookup failed on this address", 24717c478bd9Sstevel@tonic-gate "RTM_LOCK: fix specified metrics", 24727c478bd9Sstevel@tonic-gate "RTM_OLDADD: caused by SIOCADDRT", 24737c478bd9Sstevel@tonic-gate "RTM_OLDDEL: caused by SIOCDELRT", 24747c478bd9Sstevel@tonic-gate "RTM_RESOLVE: Route created by cloning", 24757c478bd9Sstevel@tonic-gate "RTM_NEWADDR: address being added to iface", 24767c478bd9Sstevel@tonic-gate "RTM_DELADDR: address being removed from iface", 24777c478bd9Sstevel@tonic-gate "RTM_IFINFO: iface status change", 24787c478bd9Sstevel@tonic-gate 0, 24797c478bd9Sstevel@tonic-gate }; 24807c478bd9Sstevel@tonic-gate 24817c478bd9Sstevel@tonic-gate #define NMSGTYPES (sizeof (msgtypes) / sizeof (msgtypes[0])) 24827c478bd9Sstevel@tonic-gate 24837c478bd9Sstevel@tonic-gate static char metricnames[] = 24847c478bd9Sstevel@tonic-gate "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount" 24857c478bd9Sstevel@tonic-gate "\1mtu"; 24867c478bd9Sstevel@tonic-gate static char routeflags[] = 24877c478bd9Sstevel@tonic-gate "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT" 24887c478bd9Sstevel@tonic-gate "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 24897c478bd9Sstevel@tonic-gate "\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC"; 24907c478bd9Sstevel@tonic-gate static char ifnetflags[] = 24917c478bd9Sstevel@tonic-gate "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP" 24927c478bd9Sstevel@tonic-gate "\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST" 24937c478bd9Sstevel@tonic-gate "\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE" 24947c478bd9Sstevel@tonic-gate "\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF" 24957c478bd9Sstevel@tonic-gate "\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6" 24967c478bd9Sstevel@tonic-gate "\033MIP\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE" 24977c478bd9Sstevel@tonic-gate "\041XRESOLV\042COS\043PREFERRED\044TEMPORARY"; 24987c478bd9Sstevel@tonic-gate static char addrnames[] = 24997c478bd9Sstevel@tonic-gate "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC"; 25007c478bd9Sstevel@tonic-gate 25017c478bd9Sstevel@tonic-gate void 25027c478bd9Sstevel@tonic-gate print_rtmsg(struct rt_msghdr *rtm, int msglen) 25037c478bd9Sstevel@tonic-gate { 25047c478bd9Sstevel@tonic-gate struct if_msghdr *ifm; 25057c478bd9Sstevel@tonic-gate struct ifa_msghdr *ifam; 25067c478bd9Sstevel@tonic-gate 25077c478bd9Sstevel@tonic-gate if (!verbose) 25087c478bd9Sstevel@tonic-gate return; 25097c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 25107c478bd9Sstevel@tonic-gate (void) printf("routing message version %d not understood\n", 25117c478bd9Sstevel@tonic-gate rtm->rtm_version); 25127c478bd9Sstevel@tonic-gate return; 25137c478bd9Sstevel@tonic-gate } 25147c478bd9Sstevel@tonic-gate if (rtm->rtm_msglen > (ushort_t)msglen) { 25157c478bd9Sstevel@tonic-gate (void) printf("message length mismatch, in packet %d, " 25167c478bd9Sstevel@tonic-gate "returned %d\n", 25177c478bd9Sstevel@tonic-gate rtm->rtm_msglen, msglen); 25187c478bd9Sstevel@tonic-gate } 25197c478bd9Sstevel@tonic-gate /* 25207c478bd9Sstevel@tonic-gate * Since rtm->rtm_type is unsigned, we'll just check the case of zero 25217c478bd9Sstevel@tonic-gate * and the upper-bound of (NMSGTYPES - 1). 25227c478bd9Sstevel@tonic-gate */ 25237c478bd9Sstevel@tonic-gate if (rtm->rtm_type == 0 || rtm->rtm_type >= (NMSGTYPES - 1)) { 25247c478bd9Sstevel@tonic-gate (void) printf("routing message type %d not understood\n", 25257c478bd9Sstevel@tonic-gate rtm->rtm_type); 25267c478bd9Sstevel@tonic-gate return; 25277c478bd9Sstevel@tonic-gate } 25287c478bd9Sstevel@tonic-gate (void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen); 25297c478bd9Sstevel@tonic-gate switch (rtm->rtm_type) { 25307c478bd9Sstevel@tonic-gate case RTM_IFINFO: 25317c478bd9Sstevel@tonic-gate ifm = (struct if_msghdr *)rtm; 25327c478bd9Sstevel@tonic-gate (void) printf("if# %d, flags:", ifm->ifm_index); 25337c478bd9Sstevel@tonic-gate bprintf(stdout, ifm->ifm_flags, ifnetflags); 25347c478bd9Sstevel@tonic-gate pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 25357c478bd9Sstevel@tonic-gate break; 25367c478bd9Sstevel@tonic-gate case RTM_NEWADDR: 25377c478bd9Sstevel@tonic-gate case RTM_DELADDR: 25387c478bd9Sstevel@tonic-gate ifam = (struct ifa_msghdr *)rtm; 25397c478bd9Sstevel@tonic-gate (void) printf("metric %d, flags:", ifam->ifam_metric); 25407c478bd9Sstevel@tonic-gate bprintf(stdout, ifam->ifam_flags, routeflags); 25417c478bd9Sstevel@tonic-gate pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); 25427c478bd9Sstevel@tonic-gate break; 25437c478bd9Sstevel@tonic-gate default: 25447c478bd9Sstevel@tonic-gate (void) printf("pid: %ld, seq %d, errno %d, flags:", 25457c478bd9Sstevel@tonic-gate rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 25467c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_flags, routeflags); 25477c478bd9Sstevel@tonic-gate pmsg_common(rtm); 25487c478bd9Sstevel@tonic-gate } 25497c478bd9Sstevel@tonic-gate } 25507c478bd9Sstevel@tonic-gate 25517c478bd9Sstevel@tonic-gate void 2552*3f33f4f7Sjl138328 print_getmsg(rtcmd_irep_t *req_rt, struct rt_msghdr *rtm, int msglen) 25537c478bd9Sstevel@tonic-gate { 25547c478bd9Sstevel@tonic-gate struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL; 25557c478bd9Sstevel@tonic-gate struct sockaddr_dl *ifp = NULL; 25567c478bd9Sstevel@tonic-gate struct sockaddr *sa; 25577c478bd9Sstevel@tonic-gate char *cp; 25587c478bd9Sstevel@tonic-gate int i; 25597c478bd9Sstevel@tonic-gate 2560*3f33f4f7Sjl138328 (void) printf(" route to: %s\n", routename(&req_rt->ri_dst.sa)); 25617c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 25627c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 25637c478bd9Sstevel@tonic-gate gettext("routing message version %d not understood\n"), 25647c478bd9Sstevel@tonic-gate rtm->rtm_version); 25657c478bd9Sstevel@tonic-gate return; 25667c478bd9Sstevel@tonic-gate } 25677c478bd9Sstevel@tonic-gate if (rtm->rtm_msglen > (ushort_t)msglen) { 25687c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 25697c478bd9Sstevel@tonic-gate gettext("message length mismatch, in packet %d, " 25707c478bd9Sstevel@tonic-gate "returned %d\n"), rtm->rtm_msglen, msglen); 25717c478bd9Sstevel@tonic-gate } 25727c478bd9Sstevel@tonic-gate if (rtm->rtm_errno) { 25737c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "RTM_GET: %s (errno %d)\n", 25747c478bd9Sstevel@tonic-gate strerror(rtm->rtm_errno), rtm->rtm_errno); 25757c478bd9Sstevel@tonic-gate return; 25767c478bd9Sstevel@tonic-gate } 25777c478bd9Sstevel@tonic-gate cp = ((char *)(rtm + 1)); 25787c478bd9Sstevel@tonic-gate if (rtm->rtm_addrs != 0) { 25797c478bd9Sstevel@tonic-gate for (i = 1; i != 0; i <<= 1) { 25807c478bd9Sstevel@tonic-gate if (i & rtm->rtm_addrs) { 25817c478bd9Sstevel@tonic-gate /* LINTED */ 25827c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)cp; 25837c478bd9Sstevel@tonic-gate switch (i) { 25847c478bd9Sstevel@tonic-gate case RTA_DST: 25857c478bd9Sstevel@tonic-gate dst = sa; 25867c478bd9Sstevel@tonic-gate break; 25877c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 25887c478bd9Sstevel@tonic-gate gate = sa; 25897c478bd9Sstevel@tonic-gate break; 25907c478bd9Sstevel@tonic-gate case RTA_NETMASK: 25917c478bd9Sstevel@tonic-gate mask = sa; 25927c478bd9Sstevel@tonic-gate break; 25937c478bd9Sstevel@tonic-gate case RTA_IFP: 25947c478bd9Sstevel@tonic-gate if (sa->sa_family == AF_LINK && 25957c478bd9Sstevel@tonic-gate ((struct sockaddr_dl *)sa)-> 25967c478bd9Sstevel@tonic-gate sdl_nlen != 0) 25977c478bd9Sstevel@tonic-gate ifp = (struct sockaddr_dl *)sa; 25987c478bd9Sstevel@tonic-gate break; 25997c478bd9Sstevel@tonic-gate case RTA_SRC: 26007c478bd9Sstevel@tonic-gate src = sa; 26017c478bd9Sstevel@tonic-gate break; 26027c478bd9Sstevel@tonic-gate } 26037c478bd9Sstevel@tonic-gate ADVANCE(cp, sa); 26047c478bd9Sstevel@tonic-gate } 26057c478bd9Sstevel@tonic-gate } 26067c478bd9Sstevel@tonic-gate } 26077c478bd9Sstevel@tonic-gate if (dst != NULL && mask != NULL) 26087c478bd9Sstevel@tonic-gate mask->sa_family = dst->sa_family; /* XXX */ 26097c478bd9Sstevel@tonic-gate if (dst != NULL) 26107c478bd9Sstevel@tonic-gate (void) printf("destination: %s\n", routename(dst)); 26117c478bd9Sstevel@tonic-gate if (mask != NULL) { 26127c478bd9Sstevel@tonic-gate boolean_t savenflag = nflag; 26137c478bd9Sstevel@tonic-gate 26147c478bd9Sstevel@tonic-gate nflag = B_TRUE; 26157c478bd9Sstevel@tonic-gate (void) printf(" mask: %s\n", routename(mask)); 26167c478bd9Sstevel@tonic-gate nflag = savenflag; 26177c478bd9Sstevel@tonic-gate } 26187c478bd9Sstevel@tonic-gate if (gate != NULL && rtm->rtm_flags & RTF_GATEWAY) 26197c478bd9Sstevel@tonic-gate (void) printf(" gateway: %s\n", routename(gate)); 26207c478bd9Sstevel@tonic-gate if (src != NULL && rtm->rtm_flags & RTF_SETSRC) 26217c478bd9Sstevel@tonic-gate (void) printf(" setsrc: %s\n", routename(src)); 26227c478bd9Sstevel@tonic-gate if (ifp != NULL) { 26237c478bd9Sstevel@tonic-gate if (verbose) { 26247c478bd9Sstevel@tonic-gate int i; 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate (void) printf(" interface: %.*s index %d address ", 26277c478bd9Sstevel@tonic-gate ifp->sdl_nlen, ifp->sdl_data, ifp->sdl_index); 26287c478bd9Sstevel@tonic-gate for (i = ifp->sdl_nlen; 26297c478bd9Sstevel@tonic-gate i < ifp->sdl_nlen + ifp->sdl_alen; 26307c478bd9Sstevel@tonic-gate i++) { 26317c478bd9Sstevel@tonic-gate (void) printf("%02x ", 26327c478bd9Sstevel@tonic-gate ifp->sdl_data[i] & 0xFF); 26337c478bd9Sstevel@tonic-gate } 26347c478bd9Sstevel@tonic-gate (void) printf("\n"); 26357c478bd9Sstevel@tonic-gate } else { 26367c478bd9Sstevel@tonic-gate (void) printf(" interface: %.*s\n", 26377c478bd9Sstevel@tonic-gate ifp->sdl_nlen, ifp->sdl_data); 26387c478bd9Sstevel@tonic-gate } 26397c478bd9Sstevel@tonic-gate } 26407c478bd9Sstevel@tonic-gate (void) printf(" flags: "); 26417c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_flags, routeflags); 26427c478bd9Sstevel@tonic-gate 26437c478bd9Sstevel@tonic-gate #define lock(f) ((rtm->rtm_rmx.rmx_locks & RTV_ ## f) ? 'L' : ' ') 26447c478bd9Sstevel@tonic-gate #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 26457c478bd9Sstevel@tonic-gate 26467c478bd9Sstevel@tonic-gate (void) printf("\n%s\n", " recvpipe sendpipe ssthresh rtt,ms " 26477c478bd9Sstevel@tonic-gate "rttvar,ms hopcount mtu expire"); 26487c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 26497c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 26507c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 26517c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 26527c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 26537c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 26547c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 26557c478bd9Sstevel@tonic-gate if (rtm->rtm_rmx.rmx_expire) 26567c478bd9Sstevel@tonic-gate rtm->rtm_rmx.rmx_expire -= time(0); 26577c478bd9Sstevel@tonic-gate (void) printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 26587c478bd9Sstevel@tonic-gate #undef lock 26597c478bd9Sstevel@tonic-gate #undef msec 26607c478bd9Sstevel@tonic-gate #define RTA_IGN \ 26617c478bd9Sstevel@tonic-gate (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC) 26627c478bd9Sstevel@tonic-gate if (verbose) { 26637c478bd9Sstevel@tonic-gate pmsg_common(rtm); 26647c478bd9Sstevel@tonic-gate } else if (rtm->rtm_addrs &~ RTA_IGN) { 26657c478bd9Sstevel@tonic-gate (void) printf("sockaddrs: "); 26667c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_addrs, addrnames); 26677c478bd9Sstevel@tonic-gate (void) putchar('\n'); 26687c478bd9Sstevel@tonic-gate } 26697c478bd9Sstevel@tonic-gate #undef RTA_IGN 26707c478bd9Sstevel@tonic-gate } 26717c478bd9Sstevel@tonic-gate 26727c478bd9Sstevel@tonic-gate void 26737c478bd9Sstevel@tonic-gate pmsg_common(struct rt_msghdr *rtm) 26747c478bd9Sstevel@tonic-gate { 26757c478bd9Sstevel@tonic-gate (void) printf("\nlocks: "); 26767c478bd9Sstevel@tonic-gate bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames); 26777c478bd9Sstevel@tonic-gate (void) printf(" inits: "); 26787c478bd9Sstevel@tonic-gate bprintf(stdout, (int)rtm->rtm_inits, metricnames); 26797c478bd9Sstevel@tonic-gate pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs); 26807c478bd9Sstevel@tonic-gate } 26817c478bd9Sstevel@tonic-gate 26827c478bd9Sstevel@tonic-gate void 26837c478bd9Sstevel@tonic-gate pmsg_addrs(char *cp, int addrs) 26847c478bd9Sstevel@tonic-gate { 26857c478bd9Sstevel@tonic-gate struct sockaddr *sa; 26867c478bd9Sstevel@tonic-gate int i; 26877c478bd9Sstevel@tonic-gate 26887c478bd9Sstevel@tonic-gate if (addrs == 0) 26897c478bd9Sstevel@tonic-gate return; 26907c478bd9Sstevel@tonic-gate (void) printf("\nsockaddrs: "); 26917c478bd9Sstevel@tonic-gate bprintf(stdout, addrs, addrnames); 26927c478bd9Sstevel@tonic-gate (void) putchar('\n'); 26937c478bd9Sstevel@tonic-gate for (i = 1; i != 0; i <<= 1) { 26947c478bd9Sstevel@tonic-gate if (i & addrs) { 26957c478bd9Sstevel@tonic-gate /* LINTED */ 26967c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)cp; 26977c478bd9Sstevel@tonic-gate (void) printf(" %s", routename(sa)); 26987c478bd9Sstevel@tonic-gate ADVANCE(cp, sa); 26997c478bd9Sstevel@tonic-gate } 27007c478bd9Sstevel@tonic-gate } 27017c478bd9Sstevel@tonic-gate (void) putchar('\n'); 27027c478bd9Sstevel@tonic-gate (void) fflush(stdout); 27037c478bd9Sstevel@tonic-gate } 27047c478bd9Sstevel@tonic-gate 27057c478bd9Sstevel@tonic-gate void 27067c478bd9Sstevel@tonic-gate bprintf(FILE *fp, int b, char *s) 27077c478bd9Sstevel@tonic-gate { 27087c478bd9Sstevel@tonic-gate int i; 27097c478bd9Sstevel@tonic-gate boolean_t gotsome = B_FALSE; 27107c478bd9Sstevel@tonic-gate 27117c478bd9Sstevel@tonic-gate if (b == 0) 27127c478bd9Sstevel@tonic-gate return; 27137c478bd9Sstevel@tonic-gate while ((i = *s++) != 0) { 27147c478bd9Sstevel@tonic-gate if (b & (1 << (i - 1))) { 27157c478bd9Sstevel@tonic-gate if (!gotsome) 27167c478bd9Sstevel@tonic-gate i = '<'; 27177c478bd9Sstevel@tonic-gate else 27187c478bd9Sstevel@tonic-gate i = ','; 27197c478bd9Sstevel@tonic-gate (void) putc(i, fp); 27207c478bd9Sstevel@tonic-gate gotsome = B_TRUE; 27217c478bd9Sstevel@tonic-gate for (; (i = *s) > ' '; s++) 27227c478bd9Sstevel@tonic-gate (void) putc(i, fp); 27237c478bd9Sstevel@tonic-gate } else { 27247c478bd9Sstevel@tonic-gate while (*s > ' ') 27257c478bd9Sstevel@tonic-gate s++; 27267c478bd9Sstevel@tonic-gate } 27277c478bd9Sstevel@tonic-gate } 27287c478bd9Sstevel@tonic-gate if (gotsome) 27297c478bd9Sstevel@tonic-gate (void) putc('>', fp); 27307c478bd9Sstevel@tonic-gate } 27317c478bd9Sstevel@tonic-gate 27327c478bd9Sstevel@tonic-gate int 27337c478bd9Sstevel@tonic-gate keyword(char *cp) 27347c478bd9Sstevel@tonic-gate { 27357c478bd9Sstevel@tonic-gate struct keytab *kt = keywords; 27367c478bd9Sstevel@tonic-gate 27377c478bd9Sstevel@tonic-gate while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 27387c478bd9Sstevel@tonic-gate kt++; 27397c478bd9Sstevel@tonic-gate return (kt->kt_i); 27407c478bd9Sstevel@tonic-gate } 27417c478bd9Sstevel@tonic-gate 27427c478bd9Sstevel@tonic-gate void 2743*3f33f4f7Sjl138328 sodump(su_t *su, char *which) 27447c478bd9Sstevel@tonic-gate { 27457c478bd9Sstevel@tonic-gate static char obuf[INET6_ADDRSTRLEN]; 27467c478bd9Sstevel@tonic-gate 27477c478bd9Sstevel@tonic-gate switch (su->sa.sa_family) { 27487c478bd9Sstevel@tonic-gate case AF_LINK: 27497c478bd9Sstevel@tonic-gate (void) printf("%s: link %s; ", 27507c478bd9Sstevel@tonic-gate which, link_ntoa(&su->sdl)); 27517c478bd9Sstevel@tonic-gate break; 27527c478bd9Sstevel@tonic-gate case AF_INET: 27537c478bd9Sstevel@tonic-gate (void) printf("%s: inet %s; ", 27547c478bd9Sstevel@tonic-gate which, inet_ntoa(su->sin.sin_addr)); 27557c478bd9Sstevel@tonic-gate break; 27567c478bd9Sstevel@tonic-gate case AF_INET6: 27577c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, (void *)&su->sin6.sin6_addr, obuf, 27587c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN) != NULL) { 27597c478bd9Sstevel@tonic-gate (void) printf("%s: inet6 %s; ", which, obuf); 27607c478bd9Sstevel@tonic-gate break; 27617c478bd9Sstevel@tonic-gate } 27627c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 27637c478bd9Sstevel@tonic-gate default: 27647c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 27657c478bd9Sstevel@tonic-gate /* NOTREACHED */ 27667c478bd9Sstevel@tonic-gate } 27677c478bd9Sstevel@tonic-gate (void) fflush(stdout); 27687c478bd9Sstevel@tonic-gate } 27697c478bd9Sstevel@tonic-gate 27707c478bd9Sstevel@tonic-gate /* States */ 27717c478bd9Sstevel@tonic-gate #define VIRGIN 0 27727c478bd9Sstevel@tonic-gate #define GOTONE 1 27737c478bd9Sstevel@tonic-gate #define GOTTWO 2 27747c478bd9Sstevel@tonic-gate #define RESET 3 27757c478bd9Sstevel@tonic-gate /* Inputs */ 27767c478bd9Sstevel@tonic-gate #define DIGIT (4*0) 27777c478bd9Sstevel@tonic-gate #define END (4*1) 27787c478bd9Sstevel@tonic-gate #define DELIM (4*2) 27797c478bd9Sstevel@tonic-gate #define LETTER (4*3) 27807c478bd9Sstevel@tonic-gate 27817c478bd9Sstevel@tonic-gate void 27827c478bd9Sstevel@tonic-gate sockaddr(char *addr, struct sockaddr *sa) 27837c478bd9Sstevel@tonic-gate { 27847c478bd9Sstevel@tonic-gate char *cp = (char *)sa; 27857c478bd9Sstevel@tonic-gate int size = salen(sa); 27867c478bd9Sstevel@tonic-gate char *cplim = cp + size; 27877c478bd9Sstevel@tonic-gate int byte = 0, state = VIRGIN, new; 27887c478bd9Sstevel@tonic-gate 27897c478bd9Sstevel@tonic-gate (void) memset(cp, 0, size); 27907c478bd9Sstevel@tonic-gate cp++; 27917c478bd9Sstevel@tonic-gate do { 27927c478bd9Sstevel@tonic-gate if ((*addr >= '0') && (*addr <= '9')) { 27937c478bd9Sstevel@tonic-gate new = *addr - '0'; 27947c478bd9Sstevel@tonic-gate } else if ((*addr >= 'a') && (*addr <= 'f')) { 27957c478bd9Sstevel@tonic-gate new = *addr - 'a' + 10; 27967c478bd9Sstevel@tonic-gate } else if ((*addr >= 'A') && (*addr <= 'F')) { 27977c478bd9Sstevel@tonic-gate new = *addr - 'A' + 10; 27987c478bd9Sstevel@tonic-gate } else if (*addr == 0) { 27997c478bd9Sstevel@tonic-gate state |= END; 28007c478bd9Sstevel@tonic-gate } else { 28017c478bd9Sstevel@tonic-gate state |= DELIM; 28027c478bd9Sstevel@tonic-gate } 28037c478bd9Sstevel@tonic-gate addr++; 28047c478bd9Sstevel@tonic-gate switch (state /* | INPUT */) { 28057c478bd9Sstevel@tonic-gate case GOTTWO | DIGIT: 28067c478bd9Sstevel@tonic-gate *cp++ = byte; 28077c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 28087c478bd9Sstevel@tonic-gate case VIRGIN | DIGIT: 28097c478bd9Sstevel@tonic-gate state = GOTONE; byte = new; continue; 28107c478bd9Sstevel@tonic-gate case GOTONE | DIGIT: 28117c478bd9Sstevel@tonic-gate state = GOTTWO; byte = new + (byte << 4); continue; 28127c478bd9Sstevel@tonic-gate default: /* | DELIM */ 28137c478bd9Sstevel@tonic-gate state = VIRGIN; *cp++ = byte; byte = 0; continue; 28147c478bd9Sstevel@tonic-gate case GOTONE | END: 28157c478bd9Sstevel@tonic-gate case GOTTWO | END: 28167c478bd9Sstevel@tonic-gate *cp++ = byte; 28177c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 28187c478bd9Sstevel@tonic-gate case VIRGIN | END: 28197c478bd9Sstevel@tonic-gate break; 28207c478bd9Sstevel@tonic-gate } 28217c478bd9Sstevel@tonic-gate break; 28227c478bd9Sstevel@tonic-gate } while (cp < cplim); 28237c478bd9Sstevel@tonic-gate } 28247c478bd9Sstevel@tonic-gate 28257c478bd9Sstevel@tonic-gate int 28267c478bd9Sstevel@tonic-gate salen(struct sockaddr *sa) 28277c478bd9Sstevel@tonic-gate { 28287c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 28297c478bd9Sstevel@tonic-gate case AF_INET: 28307c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_in)); 28317c478bd9Sstevel@tonic-gate case AF_LINK: 28327c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_dl)); 28337c478bd9Sstevel@tonic-gate case AF_INET6: 28347c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_in6)); 28357c478bd9Sstevel@tonic-gate default: 28367c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr)); 28377c478bd9Sstevel@tonic-gate } 28387c478bd9Sstevel@tonic-gate } 28397c478bd9Sstevel@tonic-gate 28407c478bd9Sstevel@tonic-gate void 28417c478bd9Sstevel@tonic-gate link_addr(const char *addr, struct sockaddr_dl *sdl) 28427c478bd9Sstevel@tonic-gate { 28437c478bd9Sstevel@tonic-gate char *cp = sdl->sdl_data; 28447c478bd9Sstevel@tonic-gate char *cplim = sizeof (struct sockaddr_dl) + (char *)sdl; 28457c478bd9Sstevel@tonic-gate int byte = 0, state = VIRGIN, new; 28467c478bd9Sstevel@tonic-gate 28477c478bd9Sstevel@tonic-gate (void) memset(sdl, 0, sizeof (struct sockaddr_dl)); 28487c478bd9Sstevel@tonic-gate sdl->sdl_family = AF_LINK; 28497c478bd9Sstevel@tonic-gate do { 28507c478bd9Sstevel@tonic-gate state &= ~LETTER; 28517c478bd9Sstevel@tonic-gate if ((*addr >= '0') && (*addr <= '9')) { 28527c478bd9Sstevel@tonic-gate new = *addr - '0'; 28537c478bd9Sstevel@tonic-gate } else if ((*addr >= 'a') && (*addr <= 'f')) { 28547c478bd9Sstevel@tonic-gate new = *addr - 'a' + 10; 28557c478bd9Sstevel@tonic-gate } else if ((*addr >= 'A') && (*addr <= 'F')) { 28567c478bd9Sstevel@tonic-gate new = *addr - 'A' + 10; 28577c478bd9Sstevel@tonic-gate } else if (*addr == 0) { 28587c478bd9Sstevel@tonic-gate state |= END; 28597c478bd9Sstevel@tonic-gate } else if (state == VIRGIN && 28607c478bd9Sstevel@tonic-gate (((*addr >= 'A') && (*addr <= 'Z')) || 28617c478bd9Sstevel@tonic-gate ((*addr >= 'a') && (*addr <= 'z')))) { 28627c478bd9Sstevel@tonic-gate state |= LETTER; 28637c478bd9Sstevel@tonic-gate } else { 28647c478bd9Sstevel@tonic-gate state |= DELIM; 28657c478bd9Sstevel@tonic-gate } 28667c478bd9Sstevel@tonic-gate addr++; 28677c478bd9Sstevel@tonic-gate switch (state /* | INPUT */) { 28687c478bd9Sstevel@tonic-gate case VIRGIN | DIGIT: 28697c478bd9Sstevel@tonic-gate case VIRGIN | LETTER: 28707c478bd9Sstevel@tonic-gate *cp++ = addr[-1]; 28717c478bd9Sstevel@tonic-gate continue; 28727c478bd9Sstevel@tonic-gate case VIRGIN | DELIM: 28737c478bd9Sstevel@tonic-gate state = RESET; 28747c478bd9Sstevel@tonic-gate sdl->sdl_nlen = cp - sdl->sdl_data; 28757c478bd9Sstevel@tonic-gate continue; 28767c478bd9Sstevel@tonic-gate case GOTTWO | DIGIT: 28777c478bd9Sstevel@tonic-gate *cp++ = byte; 28787c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 28797c478bd9Sstevel@tonic-gate case RESET | DIGIT: 28807c478bd9Sstevel@tonic-gate state = GOTONE; 28817c478bd9Sstevel@tonic-gate byte = new; 28827c478bd9Sstevel@tonic-gate continue; 28837c478bd9Sstevel@tonic-gate case GOTONE | DIGIT: 28847c478bd9Sstevel@tonic-gate state = GOTTWO; 28857c478bd9Sstevel@tonic-gate byte = new + (byte << 4); 28867c478bd9Sstevel@tonic-gate continue; 28877c478bd9Sstevel@tonic-gate default: /* | DELIM */ 28887c478bd9Sstevel@tonic-gate state = RESET; 28897c478bd9Sstevel@tonic-gate *cp++ = byte; 28907c478bd9Sstevel@tonic-gate byte = 0; 28917c478bd9Sstevel@tonic-gate continue; 28927c478bd9Sstevel@tonic-gate case GOTONE | END: 28937c478bd9Sstevel@tonic-gate case GOTTWO | END: 28947c478bd9Sstevel@tonic-gate *cp++ = byte; 28957c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 28967c478bd9Sstevel@tonic-gate case RESET | END: 28977c478bd9Sstevel@tonic-gate break; 28987c478bd9Sstevel@tonic-gate } 28997c478bd9Sstevel@tonic-gate break; 29007c478bd9Sstevel@tonic-gate } while (cp < cplim); 29017c478bd9Sstevel@tonic-gate sdl->sdl_alen = cp - LLADDR(sdl); 29027c478bd9Sstevel@tonic-gate } 29037c478bd9Sstevel@tonic-gate 29047c478bd9Sstevel@tonic-gate static char hexlist[] = "0123456789abcdef"; 29057c478bd9Sstevel@tonic-gate 29067c478bd9Sstevel@tonic-gate char * 29077c478bd9Sstevel@tonic-gate link_ntoa(const struct sockaddr_dl *sdl) 29087c478bd9Sstevel@tonic-gate { 29097c478bd9Sstevel@tonic-gate static char obuf[64]; 29107c478bd9Sstevel@tonic-gate char *out = obuf; 29117c478bd9Sstevel@tonic-gate int i; 29127c478bd9Sstevel@tonic-gate uchar_t *in = (uchar_t *)LLADDR(sdl); 29137c478bd9Sstevel@tonic-gate uchar_t *inlim = in + sdl->sdl_alen; 29147c478bd9Sstevel@tonic-gate boolean_t firsttime = B_TRUE; 29157c478bd9Sstevel@tonic-gate 29167c478bd9Sstevel@tonic-gate if (sdl->sdl_nlen) { 29177c478bd9Sstevel@tonic-gate (void) memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen); 29187c478bd9Sstevel@tonic-gate out += sdl->sdl_nlen; 29197c478bd9Sstevel@tonic-gate if (sdl->sdl_alen) 29207c478bd9Sstevel@tonic-gate *out++ = ':'; 29217c478bd9Sstevel@tonic-gate } 29227c478bd9Sstevel@tonic-gate while (in < inlim) { 29237c478bd9Sstevel@tonic-gate if (firsttime) 29247c478bd9Sstevel@tonic-gate firsttime = B_FALSE; 29257c478bd9Sstevel@tonic-gate else 29267c478bd9Sstevel@tonic-gate *out++ = '.'; 29277c478bd9Sstevel@tonic-gate i = *in++; 29287c478bd9Sstevel@tonic-gate if (i > 0xf) { 29297c478bd9Sstevel@tonic-gate out[1] = hexlist[i & 0xf]; 29307c478bd9Sstevel@tonic-gate i >>= 4; 29317c478bd9Sstevel@tonic-gate out[0] = hexlist[i]; 29327c478bd9Sstevel@tonic-gate out += 2; 29337c478bd9Sstevel@tonic-gate } else { 29347c478bd9Sstevel@tonic-gate *out++ = hexlist[i]; 29357c478bd9Sstevel@tonic-gate } 29367c478bd9Sstevel@tonic-gate } 29377c478bd9Sstevel@tonic-gate *out = 0; 29387c478bd9Sstevel@tonic-gate return (obuf); 29397c478bd9Sstevel@tonic-gate } 29407c478bd9Sstevel@tonic-gate 29417c478bd9Sstevel@tonic-gate static mib_item_t * 29427c478bd9Sstevel@tonic-gate mibget(int sd) 29437c478bd9Sstevel@tonic-gate { 29447c478bd9Sstevel@tonic-gate intmax_t buf[512 / sizeof (intmax_t)]; 29457c478bd9Sstevel@tonic-gate int flags; 29467c478bd9Sstevel@tonic-gate int i, j, getcode; 29477c478bd9Sstevel@tonic-gate struct strbuf ctlbuf, databuf; 29487c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; 29497c478bd9Sstevel@tonic-gate struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; 29507c478bd9Sstevel@tonic-gate struct T_error_ack *tea = (struct T_error_ack *)buf; 29517c478bd9Sstevel@tonic-gate struct opthdr *req; 29527c478bd9Sstevel@tonic-gate mib_item_t *first_item = NULL; 29537c478bd9Sstevel@tonic-gate mib_item_t *last_item = NULL; 29547c478bd9Sstevel@tonic-gate mib_item_t *temp; 29557c478bd9Sstevel@tonic-gate 29567c478bd9Sstevel@tonic-gate tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 29577c478bd9Sstevel@tonic-gate tor->OPT_offset = sizeof (struct T_optmgmt_req); 29587c478bd9Sstevel@tonic-gate tor->OPT_length = sizeof (struct opthdr); 29597c478bd9Sstevel@tonic-gate tor->MGMT_flags = T_CURRENT; 29607c478bd9Sstevel@tonic-gate req = (struct opthdr *)&tor[1]; 29617c478bd9Sstevel@tonic-gate req->level = MIB2_IP; /* any MIB2_xxx value ok here */ 29627c478bd9Sstevel@tonic-gate req->name = 0; 29637c478bd9Sstevel@tonic-gate req->len = 0; 29647c478bd9Sstevel@tonic-gate 29657c478bd9Sstevel@tonic-gate ctlbuf.buf = (char *)buf; 29667c478bd9Sstevel@tonic-gate ctlbuf.len = tor->OPT_length + tor->OPT_offset; 29677c478bd9Sstevel@tonic-gate flags = 0; 29687c478bd9Sstevel@tonic-gate if (putmsg(sd, &ctlbuf, NULL, flags) < 0) { 29697c478bd9Sstevel@tonic-gate perror("mibget: putmsg (ctl)"); 29707c478bd9Sstevel@tonic-gate return (NULL); 29717c478bd9Sstevel@tonic-gate } 29727c478bd9Sstevel@tonic-gate /* 29737c478bd9Sstevel@tonic-gate * each reply consists of a ctl part for one fixed structure 29747c478bd9Sstevel@tonic-gate * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK, 29757c478bd9Sstevel@tonic-gate * containing an opthdr structure. level/name identify the entry, 29767c478bd9Sstevel@tonic-gate * len is the size of the data part of the message. 29777c478bd9Sstevel@tonic-gate */ 29787c478bd9Sstevel@tonic-gate req = (struct opthdr *)&toa[1]; 29797c478bd9Sstevel@tonic-gate ctlbuf.maxlen = sizeof (buf); 29807c478bd9Sstevel@tonic-gate for (j = 1; ; j++) { 29817c478bd9Sstevel@tonic-gate flags = 0; 29827c478bd9Sstevel@tonic-gate getcode = getmsg(sd, &ctlbuf, NULL, &flags); 29837c478bd9Sstevel@tonic-gate if (getcode < 0) { 29847c478bd9Sstevel@tonic-gate perror("mibget: getmsg (ctl)"); 29857c478bd9Sstevel@tonic-gate if (verbose) { 29867c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 29877c478bd9Sstevel@tonic-gate "# level name len\n"); 29887c478bd9Sstevel@tonic-gate i = 0; 29897c478bd9Sstevel@tonic-gate for (last_item = first_item; last_item != NULL; 29907c478bd9Sstevel@tonic-gate last_item = last_item->next_item) { 29917c478bd9Sstevel@tonic-gate (void) printf("%d %4ld %5ld %ld\n", 29927c478bd9Sstevel@tonic-gate ++i, last_item->group, 29937c478bd9Sstevel@tonic-gate last_item->mib_id, 29947c478bd9Sstevel@tonic-gate last_item->length); 29957c478bd9Sstevel@tonic-gate } 29967c478bd9Sstevel@tonic-gate } 29977c478bd9Sstevel@tonic-gate break; 29987c478bd9Sstevel@tonic-gate } 29997c478bd9Sstevel@tonic-gate if (getcode == 0 && 30007c478bd9Sstevel@tonic-gate ctlbuf.len >= sizeof (struct T_optmgmt_ack) && 30017c478bd9Sstevel@tonic-gate toa->PRIM_type == T_OPTMGMT_ACK && 30027c478bd9Sstevel@tonic-gate toa->MGMT_flags == T_SUCCESS && 30037c478bd9Sstevel@tonic-gate req->len == 0) { 30047c478bd9Sstevel@tonic-gate if (verbose) { 30057c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg() %d returned EOD " 30067c478bd9Sstevel@tonic-gate "(level %lu, name %lu)\n", j, req->level, 30077c478bd9Sstevel@tonic-gate req->name); 30087c478bd9Sstevel@tonic-gate } 30097c478bd9Sstevel@tonic-gate return (first_item); /* this is EOD msg */ 30107c478bd9Sstevel@tonic-gate } 30117c478bd9Sstevel@tonic-gate 30127c478bd9Sstevel@tonic-gate if (ctlbuf.len >= sizeof (struct T_error_ack) && 30137c478bd9Sstevel@tonic-gate tea->PRIM_type == T_ERROR_ACK) { 30147c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("mibget %d gives " 30157c478bd9Sstevel@tonic-gate "T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = " 30167c478bd9Sstevel@tonic-gate "0x%lx\n"), j, tea->TLI_error, tea->UNIX_error); 30177c478bd9Sstevel@tonic-gate errno = (tea->TLI_error == TSYSERR) 30187c478bd9Sstevel@tonic-gate ? tea->UNIX_error : EPROTO; 30197c478bd9Sstevel@tonic-gate break; 30207c478bd9Sstevel@tonic-gate } 30217c478bd9Sstevel@tonic-gate 30227c478bd9Sstevel@tonic-gate if (getcode != MOREDATA || 30237c478bd9Sstevel@tonic-gate ctlbuf.len < sizeof (struct T_optmgmt_ack) || 30247c478bd9Sstevel@tonic-gate toa->PRIM_type != T_OPTMGMT_ACK || 30257c478bd9Sstevel@tonic-gate toa->MGMT_flags != T_SUCCESS) { 30267c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg(ctl) %d returned %d, " 30277c478bd9Sstevel@tonic-gate "ctlbuf.len = %d, PRIM_type = %ld\n", 30287c478bd9Sstevel@tonic-gate j, getcode, ctlbuf.len, toa->PRIM_type); 30297c478bd9Sstevel@tonic-gate if (toa->PRIM_type == T_OPTMGMT_ACK) { 30307c478bd9Sstevel@tonic-gate (void) printf("T_OPTMGMT_ACK: " 30317c478bd9Sstevel@tonic-gate "MGMT_flags = 0x%lx, req->len = %ld\n", 30327c478bd9Sstevel@tonic-gate toa->MGMT_flags, req->len); 30337c478bd9Sstevel@tonic-gate } 30347c478bd9Sstevel@tonic-gate errno = ENOMSG; 30357c478bd9Sstevel@tonic-gate break; 30367c478bd9Sstevel@tonic-gate } 30377c478bd9Sstevel@tonic-gate 30387c478bd9Sstevel@tonic-gate temp = malloc(sizeof (mib_item_t)); 30397c478bd9Sstevel@tonic-gate if (temp == NULL) { 30407c478bd9Sstevel@tonic-gate perror("mibget: malloc"); 30417c478bd9Sstevel@tonic-gate break; 30427c478bd9Sstevel@tonic-gate } 30437c478bd9Sstevel@tonic-gate if (last_item != NULL) 30447c478bd9Sstevel@tonic-gate last_item->next_item = temp; 30457c478bd9Sstevel@tonic-gate else 30467c478bd9Sstevel@tonic-gate first_item = temp; 30477c478bd9Sstevel@tonic-gate last_item = temp; 30487c478bd9Sstevel@tonic-gate last_item->next_item = NULL; 30497c478bd9Sstevel@tonic-gate last_item->group = req->level; 30507c478bd9Sstevel@tonic-gate last_item->mib_id = req->name; 30517c478bd9Sstevel@tonic-gate last_item->length = req->len; 30527c478bd9Sstevel@tonic-gate last_item->valp = malloc(req->len); 30537c478bd9Sstevel@tonic-gate if (verbose) { 30547c478bd9Sstevel@tonic-gate (void) printf("msg %d: group = %4ld mib_id = %5ld " 30557c478bd9Sstevel@tonic-gate "length = %ld\n", 30567c478bd9Sstevel@tonic-gate j, last_item->group, last_item->mib_id, 30577c478bd9Sstevel@tonic-gate last_item->length); 30587c478bd9Sstevel@tonic-gate } 30597c478bd9Sstevel@tonic-gate 30607c478bd9Sstevel@tonic-gate databuf.maxlen = last_item->length; 30617c478bd9Sstevel@tonic-gate databuf.buf = (char *)last_item->valp; 30627c478bd9Sstevel@tonic-gate databuf.len = 0; 30637c478bd9Sstevel@tonic-gate flags = 0; 30647c478bd9Sstevel@tonic-gate getcode = getmsg(sd, NULL, &databuf, &flags); 30657c478bd9Sstevel@tonic-gate if (getcode < 0) { 30667c478bd9Sstevel@tonic-gate perror("mibget: getmsg (data)"); 30677c478bd9Sstevel@tonic-gate break; 30687c478bd9Sstevel@tonic-gate } else if (getcode != 0) { 30697c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg(data) returned %d, " 30707c478bd9Sstevel@tonic-gate "databuf.maxlen = %d, databuf.len = %d\n", 30717c478bd9Sstevel@tonic-gate getcode, databuf.maxlen, databuf.len); 30727c478bd9Sstevel@tonic-gate break; 30737c478bd9Sstevel@tonic-gate } 30747c478bd9Sstevel@tonic-gate } 30757c478bd9Sstevel@tonic-gate 30767c478bd9Sstevel@tonic-gate /* 30777c478bd9Sstevel@tonic-gate * On error, free all the allocated mib_item_t objects. 30787c478bd9Sstevel@tonic-gate */ 30797c478bd9Sstevel@tonic-gate while (first_item != NULL) { 30807c478bd9Sstevel@tonic-gate last_item = first_item; 30817c478bd9Sstevel@tonic-gate first_item = first_item->next_item; 30827c478bd9Sstevel@tonic-gate free(last_item); 30837c478bd9Sstevel@tonic-gate } 30847c478bd9Sstevel@tonic-gate return (NULL); 30857c478bd9Sstevel@tonic-gate } 3086