17c478bd9Sstevel@tonic-gate /* 2*a59fa508Sjl138328 * Copyright 2006 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*a59fa508Sjl138328 #include <sys/stat.h> 557c478bd9Sstevel@tonic-gate #include <sys/stream.h> 567a23074eSdduvall #include <sys/sysmacros.h> 57*a59fa508Sjl138328 #include <sys/tihdr.h> 58*a59fa508Sjl138328 #include <sys/types.h> 59aee32e3dScarlsonj #include <sys/ccompile.h> 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate #include <net/if.h> 627c478bd9Sstevel@tonic-gate #include <net/route.h> 637c478bd9Sstevel@tonic-gate #include <net/if_dl.h> 647c478bd9Sstevel@tonic-gate #include <netinet/in.h> 657c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 667c478bd9Sstevel@tonic-gate #include <netdb.h> 677c478bd9Sstevel@tonic-gate #include <inet/mib2.h> 687c478bd9Sstevel@tonic-gate #include <inet/ip.h> 697c478bd9Sstevel@tonic-gate 70*a59fa508Sjl138328 #include <limits.h> 717c478bd9Sstevel@tonic-gate #include <locale.h> 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #include <errno.h> 747c478bd9Sstevel@tonic-gate #include <unistd.h> 757c478bd9Sstevel@tonic-gate #include <stdio.h> 767c478bd9Sstevel@tonic-gate #include <stdlib.h> 777c478bd9Sstevel@tonic-gate #include <string.h> 787c478bd9Sstevel@tonic-gate #include <stropts.h> 797c478bd9Sstevel@tonic-gate #include <fcntl.h> 80*a59fa508Sjl138328 #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*a59fa508Sjl138328 #define K_SHOW 43 170*a59fa508Sjl138328 {"show", K_SHOW}, 1717c478bd9Sstevel@tonic-gate {0, 0} 1727c478bd9Sstevel@tonic-gate }; 1737c478bd9Sstevel@tonic-gate 174*a59fa508Sjl138328 /* 175*a59fa508Sjl138328 * Size of buffers used to hold command lines from the saved route file as 176*a59fa508Sjl138328 * well as error strings. 177*a59fa508Sjl138328 */ 178*a59fa508Sjl138328 #define BUF_SIZE 2048 179*a59fa508Sjl138328 180*a59fa508Sjl138328 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*a59fa508Sjl138328 } su_t; 186*a59fa508Sjl138328 187*a59fa508Sjl138328 /* 188*a59fa508Sjl138328 * This structure represents the digested information from parsing arguments 189*a59fa508Sjl138328 * to route add, change, delete, and get. 190*a59fa508Sjl138328 * 191*a59fa508Sjl138328 */ 192*a59fa508Sjl138328 typedef struct rtcmd_irep { 193*a59fa508Sjl138328 int ri_cmd; 194*a59fa508Sjl138328 int ri_flags; 195*a59fa508Sjl138328 int ri_af; 196*a59fa508Sjl138328 ulong_t ri_inits; 197*a59fa508Sjl138328 struct rt_metrics ri_metrics; 198*a59fa508Sjl138328 int ri_addrs; 199*a59fa508Sjl138328 su_t ri_dst; 200*a59fa508Sjl138328 char *ri_dest_str; 201*a59fa508Sjl138328 su_t ri_src; 202*a59fa508Sjl138328 su_t ri_gate; 203*a59fa508Sjl138328 struct hostent *ri_gate_hp; 204*a59fa508Sjl138328 char *ri_gate_str; 205*a59fa508Sjl138328 su_t ri_mask; 206*a59fa508Sjl138328 su_t ri_ifa; 207*a59fa508Sjl138328 su_t ri_ifp; 208*a59fa508Sjl138328 char *ri_ifp_str; 209*a59fa508Sjl138328 } rtcmd_irep_t; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate typedef struct mib_item_s { 2127c478bd9Sstevel@tonic-gate struct mib_item_s *next_item; 2137c478bd9Sstevel@tonic-gate long group; 2147c478bd9Sstevel@tonic-gate long mib_id; 2157c478bd9Sstevel@tonic-gate long length; 2167c478bd9Sstevel@tonic-gate intmax_t *valp; 2177c478bd9Sstevel@tonic-gate } mib_item_t; 2187c478bd9Sstevel@tonic-gate 219*a59fa508Sjl138328 typedef enum { 220*a59fa508Sjl138328 ADDR_TYPE_ANY, 221*a59fa508Sjl138328 ADDR_TYPE_HOST, 222*a59fa508Sjl138328 ADDR_TYPE_NET 223*a59fa508Sjl138328 } addr_type_t; 2247c478bd9Sstevel@tonic-gate 225*a59fa508Sjl138328 typedef enum { 226*a59fa508Sjl138328 SEARCH_MODE_NULL, 227*a59fa508Sjl138328 SEARCH_MODE_PRINT, 228*a59fa508Sjl138328 SEARCH_MODE_DEL 229*a59fa508Sjl138328 } search_mode_t; 230*a59fa508Sjl138328 231*a59fa508Sjl138328 static boolean_t args_to_rtcmd(rtcmd_irep_t *rcip, char **argv, 232*a59fa508Sjl138328 char *cmd_string); 2337c478bd9Sstevel@tonic-gate static void bprintf(FILE *fp, int b, char *s); 234*a59fa508Sjl138328 static boolean_t compare_rtcmd(rtcmd_irep_t *srch_rt, 235*a59fa508Sjl138328 rtcmd_irep_t *file_rt); 2367c478bd9Sstevel@tonic-gate static void delRouteEntry(mib2_ipRouteEntry_t *rp, 2377c478bd9Sstevel@tonic-gate mib2_ipv6RouteEntry_t *rp6, int seqno); 238*a59fa508Sjl138328 static void del_rtcmd_irep(rtcmd_irep_t *rcip); 2397c478bd9Sstevel@tonic-gate static void flushroutes(int argc, char *argv[]); 240*a59fa508Sjl138328 static boolean_t getaddr(rtcmd_irep_t *rcip, int which, char *s, 241*a59fa508Sjl138328 addr_type_t atype); 2427c478bd9Sstevel@tonic-gate static boolean_t in6_getaddr(char *s, struct sockaddr_in6 *sin6, 2437c478bd9Sstevel@tonic-gate int *plenp, struct hostent **hpp); 2447c478bd9Sstevel@tonic-gate static boolean_t in_getaddr(char *s, struct sockaddr_in *sin, 245*a59fa508Sjl138328 int *plenp, int which, struct hostent **hpp, addr_type_t atype, 246*a59fa508Sjl138328 rtcmd_irep_t *rcip); 2477c478bd9Sstevel@tonic-gate static int in_getprefixlen(char *addr, int max_plen); 2487c478bd9Sstevel@tonic-gate static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 2497c478bd9Sstevel@tonic-gate uchar_t *mask); 250*a59fa508Sjl138328 static void inet_makenetandmask(rtcmd_irep_t *rcip, in_addr_t net, 2517c478bd9Sstevel@tonic-gate struct sockaddr_in *sin); 2527c478bd9Sstevel@tonic-gate static in_addr_t inet_makesubnetmask(in_addr_t addr, in_addr_t mask); 253*a59fa508Sjl138328 static int keyword(const char *cp); 2547c478bd9Sstevel@tonic-gate static void link_addr(const char *addr, struct sockaddr_dl *sdl); 2557c478bd9Sstevel@tonic-gate static char *link_ntoa(const struct sockaddr_dl *sdl); 2567c478bd9Sstevel@tonic-gate static mib_item_t *mibget(int sd); 2577c478bd9Sstevel@tonic-gate static char *netname(struct sockaddr *sa); 258*a59fa508Sjl138328 static int newroute(char **argv); 259*a59fa508Sjl138328 static rtcmd_irep_t *new_rtcmd_irep(void); 2607c478bd9Sstevel@tonic-gate static void pmsg_addrs(char *cp, int addrs); 2617c478bd9Sstevel@tonic-gate static void pmsg_common(struct rt_msghdr *rtm); 262*a59fa508Sjl138328 static void print_getmsg(rtcmd_irep_t *req_rt, 263*a59fa508Sjl138328 struct rt_msghdr *rtm, int msglen); 264*a59fa508Sjl138328 static void print_rtcmd_short(FILE *to, rtcmd_irep_t *rcip, 265*a59fa508Sjl138328 boolean_t gw_good, boolean_t to_saved); 2667c478bd9Sstevel@tonic-gate static void print_rtmsg(struct rt_msghdr *rtm, int msglen); 267aee32e3dScarlsonj static void quit(char *s, int err) __NORETURN; 2687c478bd9Sstevel@tonic-gate static char *routename(struct sockaddr *sa); 2697c478bd9Sstevel@tonic-gate static void rtmonitor(int argc, char *argv[]); 270*a59fa508Sjl138328 static int rtmsg(rtcmd_irep_t *rcip); 2717c478bd9Sstevel@tonic-gate static int salen(struct sockaddr *sa); 272*a59fa508Sjl138328 static void save_route(int argc, char **argv, int do_flush); 273*a59fa508Sjl138328 static void save_string(char **dst, char *src); 274*a59fa508Sjl138328 static int search_rtfile(FILE *fp, FILE *temp_fp, rtcmd_irep_t *rt, 275*a59fa508Sjl138328 search_mode_t mode); 276*a59fa508Sjl138328 static void set_metric(rtcmd_irep_t *rcip, char *value, int key, 277*a59fa508Sjl138328 boolean_t lock); 278*a59fa508Sjl138328 static int show_saved_routes(int argc); 2797c478bd9Sstevel@tonic-gate static void sockaddr(char *addr, struct sockaddr *sa); 280*a59fa508Sjl138328 static void sodump(su_t *su, char *which); 281*a59fa508Sjl138328 static void syntax_arg_missing(char *keyword); 282*a59fa508Sjl138328 static void syntax_bad_keyword(char *keyword); 283*a59fa508Sjl138328 static void syntax_error(char *err, ...); 2847c478bd9Sstevel@tonic-gate static void usage(char *cp); 285*a59fa508Sjl138328 static void write_to_rtfile(FILE *fp, int argc, char **argv); 2867c478bd9Sstevel@tonic-gate 287*a59fa508Sjl138328 static pid_t pid; 2887c478bd9Sstevel@tonic-gate static int s; 289*a59fa508Sjl138328 static boolean_t nflag; 2907c478bd9Sstevel@tonic-gate static int af = AF_INET; 2917c478bd9Sstevel@tonic-gate static boolean_t qflag, tflag; 292*a59fa508Sjl138328 static boolean_t verbose; 293*a59fa508Sjl138328 static boolean_t debugonly; 2947c478bd9Sstevel@tonic-gate static boolean_t fflag; 295*a59fa508Sjl138328 static boolean_t update_table; 296*a59fa508Sjl138328 static boolean_t perm_flag; 297*a59fa508Sjl138328 static boolean_t early_v6_keyword; 298*a59fa508Sjl138328 static char perm_file_sfx[] = "/etc/inet/static_routes"; 299*a59fa508Sjl138328 static char *perm_file; 300*a59fa508Sjl138328 static char temp_file_sfx[] = "/etc/inet/static_routes.tmp"; 301*a59fa508Sjl138328 static char *temp_file; 302*a59fa508Sjl138328 static struct in6_addr in6_host_mask = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 303*a59fa508Sjl138328 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 304*a59fa508Sjl138328 /* 305*a59fa508Sjl138328 * WARNING: 306*a59fa508Sjl138328 * This next variable indicates whether certain functions exit when an error 307*a59fa508Sjl138328 * is detected in the user input. Currently, exit_on_error is only set false 308*a59fa508Sjl138328 * in search_rtfile(), when argument are being parsed. Only those functions 309*a59fa508Sjl138328 * used by search_rtfile() to parse its arguments are designed to work in 310*a59fa508Sjl138328 * both modes. Take particular care in setting this false to ensure that any 311*a59fa508Sjl138328 * functions you call that might act on this flag properly return errors when 312*a59fa508Sjl138328 * exit_on_error is false. 313*a59fa508Sjl138328 */ 314*a59fa508Sjl138328 static int exit_on_error = B_TRUE; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate static struct { 3177c478bd9Sstevel@tonic-gate struct rt_msghdr m_rtm; 3187c478bd9Sstevel@tonic-gate char m_space[512]; 3197c478bd9Sstevel@tonic-gate } m_rtmsg; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /* 3227c478bd9Sstevel@tonic-gate * Sizes of data structures extracted from the base mib. 3237c478bd9Sstevel@tonic-gate * This allows the size of the tables entries to grow while preserving 3247c478bd9Sstevel@tonic-gate * binary compatibility. 3257c478bd9Sstevel@tonic-gate */ 3267c478bd9Sstevel@tonic-gate static int ipRouteEntrySize; 3277c478bd9Sstevel@tonic-gate static int ipv6RouteEntrySize; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate #define ROUNDUP_LONG(a) \ 3307c478bd9Sstevel@tonic-gate ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long)) 3317c478bd9Sstevel@tonic-gate #define ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n))) 3327c478bd9Sstevel@tonic-gate #define C(x) ((x) & 0xff) 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate /* 3357c478bd9Sstevel@tonic-gate * return values from in_getprefixlen() 3367c478bd9Sstevel@tonic-gate */ 3377c478bd9Sstevel@tonic-gate #define BAD_ADDR -1 /* prefix is invalid */ 3387c478bd9Sstevel@tonic-gate #define NO_PREFIX -2 /* no prefix was found */ 3397c478bd9Sstevel@tonic-gate 340*a59fa508Sjl138328 3417c478bd9Sstevel@tonic-gate void 3427c478bd9Sstevel@tonic-gate usage(char *cp) 3437c478bd9Sstevel@tonic-gate { 344*a59fa508Sjl138328 if (cp != NULL) { 3457c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: botched keyword: %s\n"), 3467c478bd9Sstevel@tonic-gate cp); 347*a59fa508Sjl138328 } 348*a59fa508Sjl138328 (void) fprintf(stderr, gettext("usage: route [ -fnpqv ] " 349*a59fa508Sjl138328 "[ -R <root-dir> ] cmd [[ -<qualifers> ] args ]\n")); 3507c478bd9Sstevel@tonic-gate exit(1); 3517c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate 354*a59fa508Sjl138328 /*PRINTFLIKE1*/ 355*a59fa508Sjl138328 void 356*a59fa508Sjl138328 syntax_error(char *err, ...) 357*a59fa508Sjl138328 { 358*a59fa508Sjl138328 va_list args; 359*a59fa508Sjl138328 360*a59fa508Sjl138328 if (exit_on_error) { 361*a59fa508Sjl138328 va_start(args, err); 362*a59fa508Sjl138328 (void) vfprintf(stderr, err, args); 363*a59fa508Sjl138328 va_end(args); 364*a59fa508Sjl138328 exit(1); 365*a59fa508Sjl138328 } 366*a59fa508Sjl138328 /* NOTREACHED */ 367*a59fa508Sjl138328 } 368*a59fa508Sjl138328 369*a59fa508Sjl138328 void 370*a59fa508Sjl138328 syntax_bad_keyword(char *keyword) 371*a59fa508Sjl138328 { 372*a59fa508Sjl138328 syntax_error(gettext("route: botched keyword: %s\n"), keyword); 373*a59fa508Sjl138328 } 374*a59fa508Sjl138328 375*a59fa508Sjl138328 void 376*a59fa508Sjl138328 syntax_arg_missing(char *keyword) 377*a59fa508Sjl138328 { 378*a59fa508Sjl138328 syntax_error(gettext("route: argument required following keyword %s\n"), 379*a59fa508Sjl138328 keyword); 380*a59fa508Sjl138328 } 381*a59fa508Sjl138328 3827c478bd9Sstevel@tonic-gate void 3837c478bd9Sstevel@tonic-gate quit(char *s, int sverrno) 3847c478bd9Sstevel@tonic-gate { 3857c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "route: "); 3867c478bd9Sstevel@tonic-gate if (s != NULL) 3877c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", s); 3887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", strerror(sverrno)); 3897c478bd9Sstevel@tonic-gate exit(sverrno); 3907c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate int 3947c478bd9Sstevel@tonic-gate main(int argc, char **argv) 3957c478bd9Sstevel@tonic-gate { 3967c478bd9Sstevel@tonic-gate extern int optind; 397*a59fa508Sjl138328 extern char *optarg; 3987c478bd9Sstevel@tonic-gate int ch; 399*a59fa508Sjl138328 int rval; 400*a59fa508Sjl138328 size_t size; 401*a59fa508Sjl138328 const char *root_dir = NULL; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 4067c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 4077c478bd9Sstevel@tonic-gate #endif 4087c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate if (argc < 2) 4117c478bd9Sstevel@tonic-gate usage((char *)NULL); 4127c478bd9Sstevel@tonic-gate 413*a59fa508Sjl138328 while ((ch = getopt(argc, argv, "R:nqdtvfp")) != EOF) { 4147c478bd9Sstevel@tonic-gate switch (ch) { 4157c478bd9Sstevel@tonic-gate case 'n': 4167c478bd9Sstevel@tonic-gate nflag = B_TRUE; 4177c478bd9Sstevel@tonic-gate break; 4187c478bd9Sstevel@tonic-gate case 'q': 4197c478bd9Sstevel@tonic-gate qflag = B_TRUE; 4207c478bd9Sstevel@tonic-gate break; 4217c478bd9Sstevel@tonic-gate case 'v': 4227c478bd9Sstevel@tonic-gate verbose = B_TRUE; 4237c478bd9Sstevel@tonic-gate break; 4247c478bd9Sstevel@tonic-gate case 't': 4257c478bd9Sstevel@tonic-gate tflag = B_TRUE; 4267c478bd9Sstevel@tonic-gate break; 4277c478bd9Sstevel@tonic-gate case 'd': 4287c478bd9Sstevel@tonic-gate debugonly = B_TRUE; 4297c478bd9Sstevel@tonic-gate break; 4307c478bd9Sstevel@tonic-gate case 'f': 4317c478bd9Sstevel@tonic-gate fflag = B_TRUE; 4327c478bd9Sstevel@tonic-gate break; 433*a59fa508Sjl138328 case 'p': 434*a59fa508Sjl138328 perm_flag = B_TRUE; 435*a59fa508Sjl138328 break; 436*a59fa508Sjl138328 case 'R': 437*a59fa508Sjl138328 root_dir = optarg; 438*a59fa508Sjl138328 break; 4397c478bd9Sstevel@tonic-gate case '?': 4407c478bd9Sstevel@tonic-gate default: 4417c478bd9Sstevel@tonic-gate usage((char *)NULL); 4427c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate argc -= optind; 4467c478bd9Sstevel@tonic-gate argv += optind; 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate pid = getpid(); 4497c478bd9Sstevel@tonic-gate if (tflag) 4507c478bd9Sstevel@tonic-gate s = open("/dev/null", O_WRONLY); 4517c478bd9Sstevel@tonic-gate else 4527c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, 0); 4537c478bd9Sstevel@tonic-gate if (s < 0) 4547c478bd9Sstevel@tonic-gate quit("socket", errno); 455*a59fa508Sjl138328 456*a59fa508Sjl138328 /* 457*a59fa508Sjl138328 * Handle the -p and -R flags. The -R flag only applies 458*a59fa508Sjl138328 * when the -p flag is set. 459*a59fa508Sjl138328 */ 460*a59fa508Sjl138328 if (root_dir == NULL) { 461*a59fa508Sjl138328 perm_file = perm_file_sfx; 462*a59fa508Sjl138328 temp_file = temp_file_sfx; 463*a59fa508Sjl138328 } else { 464*a59fa508Sjl138328 size = strlen(root_dir) + sizeof (perm_file_sfx); 465*a59fa508Sjl138328 perm_file = malloc(size); 466*a59fa508Sjl138328 if (perm_file == NULL) 467*a59fa508Sjl138328 quit("malloc", errno); 468*a59fa508Sjl138328 (void) snprintf(perm_file, size, "%s%s", root_dir, 469*a59fa508Sjl138328 perm_file_sfx); 470*a59fa508Sjl138328 size = strlen(root_dir) + sizeof (temp_file_sfx); 471*a59fa508Sjl138328 temp_file = malloc(size); 472*a59fa508Sjl138328 if (temp_file == NULL) 473*a59fa508Sjl138328 quit("malloc", errno); 474*a59fa508Sjl138328 (void) snprintf(temp_file, size, "%s%s", root_dir, 475*a59fa508Sjl138328 temp_file_sfx); 476*a59fa508Sjl138328 } 477*a59fa508Sjl138328 /* 478*a59fa508Sjl138328 * Whether or not to act on the routing table. The only time the 479*a59fa508Sjl138328 * routing table is not modified is when both -p and -R are present. 480*a59fa508Sjl138328 */ 481*a59fa508Sjl138328 update_table = (!perm_flag || root_dir == NULL); 482*a59fa508Sjl138328 if (tflag) 483*a59fa508Sjl138328 perm_flag = 0; 484*a59fa508Sjl138328 4857c478bd9Sstevel@tonic-gate if (fflag) { 4867c478bd9Sstevel@tonic-gate /* 4877c478bd9Sstevel@tonic-gate * Accept an address family keyword after the -f. Since the 4887c478bd9Sstevel@tonic-gate * default address family is AF_INET, reassign af only for the 4897c478bd9Sstevel@tonic-gate * other valid address families. 4907c478bd9Sstevel@tonic-gate */ 4917c478bd9Sstevel@tonic-gate if (*argv != NULL) { 492*a59fa508Sjl138328 switch (keyword(*argv)) { 4937c478bd9Sstevel@tonic-gate case K_INET6: 4947c478bd9Sstevel@tonic-gate af = AF_INET6; 495*a59fa508Sjl138328 early_v6_keyword = B_TRUE; 496*a59fa508Sjl138328 /* fallthrough */ 497*a59fa508Sjl138328 case K_INET: 4987c478bd9Sstevel@tonic-gate /* Skip over the address family parameter. */ 4997c478bd9Sstevel@tonic-gate argc--; 5007c478bd9Sstevel@tonic-gate argv++; 5017c478bd9Sstevel@tonic-gate break; 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate flushroutes(0, NULL); 5057c478bd9Sstevel@tonic-gate } 506*a59fa508Sjl138328 5077c478bd9Sstevel@tonic-gate if (*argv != NULL) { 5087c478bd9Sstevel@tonic-gate switch (keyword(*argv)) { 5097c478bd9Sstevel@tonic-gate case K_GET: 5107c478bd9Sstevel@tonic-gate case K_CHANGE: 5117c478bd9Sstevel@tonic-gate case K_ADD: 5127c478bd9Sstevel@tonic-gate case K_DELETE: 513*a59fa508Sjl138328 rval = 0; 514*a59fa508Sjl138328 if (update_table) { 515*a59fa508Sjl138328 rval = newroute(argv); 516*a59fa508Sjl138328 } 517*a59fa508Sjl138328 if (perm_flag && (rval == 0 || rval == EEXIST || 518*a59fa508Sjl138328 rval == ESRCH)) { 519*a59fa508Sjl138328 save_route(argc, argv, B_FALSE); 520*a59fa508Sjl138328 return (0); 521*a59fa508Sjl138328 } 522*a59fa508Sjl138328 return (rval); 523*a59fa508Sjl138328 case K_SHOW: 524*a59fa508Sjl138328 if (perm_flag) { 525*a59fa508Sjl138328 return (show_saved_routes(argc)); 526*a59fa508Sjl138328 } else { 527*a59fa508Sjl138328 syntax_error(gettext( 528*a59fa508Sjl138328 "route: show command requires -p\n")); 529*a59fa508Sjl138328 } 530*a59fa508Sjl138328 /* NOTREACHED */ 5317c478bd9Sstevel@tonic-gate case K_MONITOR: 5327c478bd9Sstevel@tonic-gate rtmonitor(argc, argv); 5337c478bd9Sstevel@tonic-gate /* NOTREACHED */ 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate case K_FLUSH: 5367c478bd9Sstevel@tonic-gate flushroutes(argc, argv); 537*a59fa508Sjl138328 return (0); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate if (!fflag) 5417c478bd9Sstevel@tonic-gate usage(*argv); 5427c478bd9Sstevel@tonic-gate return (0); 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate /* 5467c478bd9Sstevel@tonic-gate * Purge all entries in the routing tables not 5477c478bd9Sstevel@tonic-gate * associated with network interfaces. 5487c478bd9Sstevel@tonic-gate */ 5497c478bd9Sstevel@tonic-gate void 5507c478bd9Sstevel@tonic-gate flushroutes(int argc, char *argv[]) 5517c478bd9Sstevel@tonic-gate { 5527c478bd9Sstevel@tonic-gate int seqno; 5537c478bd9Sstevel@tonic-gate int sd; /* mib stream */ 5547c478bd9Sstevel@tonic-gate mib_item_t *item; 5557c478bd9Sstevel@tonic-gate mib2_ipRouteEntry_t *rp; 5567c478bd9Sstevel@tonic-gate mib2_ipv6RouteEntry_t *rp6; 5577c478bd9Sstevel@tonic-gate int oerrno; 5587c478bd9Sstevel@tonic-gate int off = 0; 5597c478bd9Sstevel@tonic-gate int on = 1; 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate if (argc > 1) { 5627c478bd9Sstevel@tonic-gate argv++; 5637c478bd9Sstevel@tonic-gate if (argc == 2 && **argv == '-') { 5647c478bd9Sstevel@tonic-gate /* 5657c478bd9Sstevel@tonic-gate * The address family (preceded by a dash) may be used 5667c478bd9Sstevel@tonic-gate * to flush the routes of that particular family. 5677c478bd9Sstevel@tonic-gate */ 5687c478bd9Sstevel@tonic-gate switch (keyword(*argv + 1)) { 5697c478bd9Sstevel@tonic-gate case K_INET: 5707c478bd9Sstevel@tonic-gate af = AF_INET; 5717c478bd9Sstevel@tonic-gate break; 5727c478bd9Sstevel@tonic-gate case K_LINK: 5737c478bd9Sstevel@tonic-gate af = AF_LINK; 5747c478bd9Sstevel@tonic-gate break; 5757c478bd9Sstevel@tonic-gate case K_INET6: 5767c478bd9Sstevel@tonic-gate af = AF_INET6; 5777c478bd9Sstevel@tonic-gate break; 5787c478bd9Sstevel@tonic-gate default: 5797c478bd9Sstevel@tonic-gate usage(*argv); 5807c478bd9Sstevel@tonic-gate /* NOTREACHED */ 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate } else { 5837c478bd9Sstevel@tonic-gate usage(*argv); 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate } 586*a59fa508Sjl138328 if (perm_flag) { 587*a59fa508Sjl138328 /* This flushes the persistent route file */ 588*a59fa508Sjl138328 save_route(0, NULL, B_TRUE); 589*a59fa508Sjl138328 } 590*a59fa508Sjl138328 if (!update_table) { 591*a59fa508Sjl138328 return; 592*a59fa508Sjl138328 } 593*a59fa508Sjl138328 594*a59fa508Sjl138328 if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off, 595*a59fa508Sjl138328 sizeof (off)) < 0) 596*a59fa508Sjl138328 quit("setsockopt", errno); 597*a59fa508Sjl138328 5987c478bd9Sstevel@tonic-gate sd = open("/dev/ip", O_RDWR); 5997c478bd9Sstevel@tonic-gate oerrno = errno; 6007c478bd9Sstevel@tonic-gate if (sd < 0) { 6017c478bd9Sstevel@tonic-gate switch (errno) { 6027c478bd9Sstevel@tonic-gate case EACCES: 6037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6047c478bd9Sstevel@tonic-gate gettext("route: flush: insufficient privileges\n")); 6057c478bd9Sstevel@tonic-gate exit(oerrno); 6067c478bd9Sstevel@tonic-gate /* NOTREACHED */ 6077c478bd9Sstevel@tonic-gate default: 6087c478bd9Sstevel@tonic-gate quit(gettext("can't open mib stream"), oerrno); 6097c478bd9Sstevel@tonic-gate /* NOTREACHED */ 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate if ((item = mibget(sd)) == NULL) 6137c478bd9Sstevel@tonic-gate quit("mibget", errno); 6147c478bd9Sstevel@tonic-gate if (verbose) { 6157c478bd9Sstevel@tonic-gate (void) printf("Examining routing table from " 6167c478bd9Sstevel@tonic-gate "T_SVR4_OPTMGMT_REQ\n"); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate seqno = 0; /* ??? */ 6197c478bd9Sstevel@tonic-gate switch (af) { 6207c478bd9Sstevel@tonic-gate case AF_INET: 6217c478bd9Sstevel@tonic-gate /* Extract ipRouteEntrySize */ 6227c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 6237c478bd9Sstevel@tonic-gate if (item->mib_id != 0) 6247c478bd9Sstevel@tonic-gate continue; 6257c478bd9Sstevel@tonic-gate if (item->group == MIB2_IP) { 6267c478bd9Sstevel@tonic-gate ipRouteEntrySize = 6277c478bd9Sstevel@tonic-gate ((mib2_ip_t *)item->valp)->ipRouteEntrySize; 6287c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(ipRouteEntrySize, 6297c478bd9Sstevel@tonic-gate sizeof (mib2_ipRouteEntry_t *))); 6307c478bd9Sstevel@tonic-gate break; 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate if (ipRouteEntrySize == 0) { 6347c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6357c478bd9Sstevel@tonic-gate gettext("ipRouteEntrySize can't be determined.\n")); 6367c478bd9Sstevel@tonic-gate exit(1); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 6397c478bd9Sstevel@tonic-gate /* 6407c478bd9Sstevel@tonic-gate * skip all the other trash that comes up the mib stream 6417c478bd9Sstevel@tonic-gate */ 6427c478bd9Sstevel@tonic-gate if (item->group != MIB2_IP || 6437c478bd9Sstevel@tonic-gate item->mib_id != MIB2_IP_ROUTE) 6447c478bd9Sstevel@tonic-gate continue; 6457c478bd9Sstevel@tonic-gate for (rp = (mib2_ipRouteEntry_t *)item->valp; 6467c478bd9Sstevel@tonic-gate (char *)rp < (char *)item->valp + item->length; 6477c478bd9Sstevel@tonic-gate /* LINTED */ 6487c478bd9Sstevel@tonic-gate rp = (mib2_ipRouteEntry_t *) 6497c478bd9Sstevel@tonic-gate ((char *)rp + ipRouteEntrySize)) { 6507c478bd9Sstevel@tonic-gate delRouteEntry(rp, NULL, seqno); 6517c478bd9Sstevel@tonic-gate seqno++; 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate break; 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate break; 6567c478bd9Sstevel@tonic-gate case AF_INET6: 6577c478bd9Sstevel@tonic-gate /* Extract ipv6RouteEntrySize */ 6587c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 6597c478bd9Sstevel@tonic-gate if (item->mib_id != 0) 6607c478bd9Sstevel@tonic-gate continue; 6617c478bd9Sstevel@tonic-gate if (item->group == MIB2_IP6) { 6627c478bd9Sstevel@tonic-gate ipv6RouteEntrySize = 6637c478bd9Sstevel@tonic-gate ((mib2_ipv6IfStatsEntry_t *)item->valp)-> 6647c478bd9Sstevel@tonic-gate ipv6RouteEntrySize; 6657c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(ipv6RouteEntrySize, 6667c478bd9Sstevel@tonic-gate sizeof (mib2_ipv6RouteEntry_t *))); 6677c478bd9Sstevel@tonic-gate break; 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate if (ipv6RouteEntrySize == 0) { 6717c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6727c478bd9Sstevel@tonic-gate "ipv6RouteEntrySize cannot be determined.\n")); 6737c478bd9Sstevel@tonic-gate exit(1); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 6767c478bd9Sstevel@tonic-gate /* 6777c478bd9Sstevel@tonic-gate * skip all the other trash that comes up the mib stream 6787c478bd9Sstevel@tonic-gate */ 6797c478bd9Sstevel@tonic-gate if (item->group != MIB2_IP6 || 6807c478bd9Sstevel@tonic-gate item->mib_id != MIB2_IP6_ROUTE) 6817c478bd9Sstevel@tonic-gate continue; 6827c478bd9Sstevel@tonic-gate for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp; 6837c478bd9Sstevel@tonic-gate (char *)rp6 < (char *)item->valp + item->length; 6847c478bd9Sstevel@tonic-gate /* LINTED */ 6857c478bd9Sstevel@tonic-gate rp6 = (mib2_ipv6RouteEntry_t *) 6867c478bd9Sstevel@tonic-gate ((char *)rp6 + ipv6RouteEntrySize)) { 6877c478bd9Sstevel@tonic-gate delRouteEntry(NULL, rp6, seqno); 6887c478bd9Sstevel@tonic-gate seqno++; 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate break; 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate break; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, 6967c478bd9Sstevel@tonic-gate sizeof (on)) < 0) 6977c478bd9Sstevel@tonic-gate quit("setsockopt", errno); 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* 7017c478bd9Sstevel@tonic-gate * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or 7027c478bd9Sstevel@tonic-gate * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in 7037c478bd9Sstevel@tonic-gate * order to facilitate the flushing of RTF_GATEWAY routes. 7047c478bd9Sstevel@tonic-gate */ 7057c478bd9Sstevel@tonic-gate static void 7067c478bd9Sstevel@tonic-gate delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno) 7077c478bd9Sstevel@tonic-gate { 7087c478bd9Sstevel@tonic-gate char *cp; 7097c478bd9Sstevel@tonic-gate int ire_type; 7107c478bd9Sstevel@tonic-gate int rlen; 7117c478bd9Sstevel@tonic-gate struct rt_msghdr *rtm; 7127c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 7137c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 7147c478bd9Sstevel@tonic-gate int slen; 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate if (rp != NULL) 7177c478bd9Sstevel@tonic-gate ire_type = rp->ipRouteInfo.re_ire_type; 7187c478bd9Sstevel@tonic-gate else 7197c478bd9Sstevel@tonic-gate ire_type = rp6->ipv6RouteInfo.re_ire_type; 7207c478bd9Sstevel@tonic-gate if (ire_type != IRE_DEFAULT && 7217c478bd9Sstevel@tonic-gate ire_type != IRE_PREFIX && 7227c478bd9Sstevel@tonic-gate ire_type != IRE_HOST && 7237c478bd9Sstevel@tonic-gate ire_type != IRE_HOST_REDIRECT) 7247c478bd9Sstevel@tonic-gate return; 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate rtm = &m_rtmsg.m_rtm; 7277c478bd9Sstevel@tonic-gate (void) memset(rtm, 0, sizeof (m_rtmsg)); 7287c478bd9Sstevel@tonic-gate rtm->rtm_type = RTM_DELETE; 7297c478bd9Sstevel@tonic-gate rtm->rtm_seq = seqno; 7307c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_GATEWAY; 7317c478bd9Sstevel@tonic-gate rtm->rtm_version = RTM_VERSION; 7327c478bd9Sstevel@tonic-gate rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 7337c478bd9Sstevel@tonic-gate cp = m_rtmsg.m_space; 7347c478bd9Sstevel@tonic-gate if (rp != NULL) { 7357c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in); 7367c478bd9Sstevel@tonic-gate if (rp->ipRouteMask == IP_HOST_MASK) 7377c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_HOST; 7387c478bd9Sstevel@tonic-gate (void) memset(&sin, 0, slen); 7397c478bd9Sstevel@tonic-gate sin.sin_family = AF_INET; 7407c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteDest; 7417c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 7427c478bd9Sstevel@tonic-gate cp += slen; 7437c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteNextHop; 7447c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 7457c478bd9Sstevel@tonic-gate cp += slen; 7467c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteMask; 7477c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 7487c478bd9Sstevel@tonic-gate cp += slen; 7497c478bd9Sstevel@tonic-gate } else { 7507c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in6); 7517c478bd9Sstevel@tonic-gate if (rp6->ipv6RoutePfxLength == IPV6_ABITS) 7527c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_HOST; 7537c478bd9Sstevel@tonic-gate (void) memset(&sin6, 0, slen); 7547c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 7557c478bd9Sstevel@tonic-gate sin6.sin6_addr = rp6->ipv6RouteDest; 7567c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 7577c478bd9Sstevel@tonic-gate cp += slen; 7587c478bd9Sstevel@tonic-gate sin6.sin6_addr = rp6->ipv6RouteNextHop; 7597c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 7607c478bd9Sstevel@tonic-gate cp += slen; 7617c478bd9Sstevel@tonic-gate (void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr)); 7627c478bd9Sstevel@tonic-gate (void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS, 7637c478bd9Sstevel@tonic-gate (uchar_t *)&sin6.sin6_addr.s6_addr); 7647c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 7657c478bd9Sstevel@tonic-gate cp += slen; 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate rtm->rtm_msglen = cp - (char *)&m_rtmsg; 7687c478bd9Sstevel@tonic-gate if (debugonly) { 7697c478bd9Sstevel@tonic-gate /* 7707c478bd9Sstevel@tonic-gate * In debugonly mode, the routing socket message to delete the 7717c478bd9Sstevel@tonic-gate * current entry is not actually sent. However if verbose is 7727c478bd9Sstevel@tonic-gate * also set, the routing socket message that would have been 7737c478bd9Sstevel@tonic-gate * is printed. 7747c478bd9Sstevel@tonic-gate */ 7757c478bd9Sstevel@tonic-gate if (verbose) 7767c478bd9Sstevel@tonic-gate print_rtmsg(rtm, rtm->rtm_msglen); 7777c478bd9Sstevel@tonic-gate return; 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen); 7817c478bd9Sstevel@tonic-gate if (rlen < (int)rtm->rtm_msglen) { 7827c478bd9Sstevel@tonic-gate if (rlen < 0) { 7837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7847c478bd9Sstevel@tonic-gate gettext("route: write to routing socket: %s\n"), 7857c478bd9Sstevel@tonic-gate strerror(errno)); 7867c478bd9Sstevel@tonic-gate } else { 7877c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: write to " 7887c478bd9Sstevel@tonic-gate "routing socket got only %d for rlen\n"), rlen); 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate return; 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate if (qflag) { 7937c478bd9Sstevel@tonic-gate /* 7947c478bd9Sstevel@tonic-gate * In quiet mode, nothing is printed at all (unless the write() 7957c478bd9Sstevel@tonic-gate * itself failed. 7967c478bd9Sstevel@tonic-gate */ 7977c478bd9Sstevel@tonic-gate return; 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate if (verbose) { 8007c478bd9Sstevel@tonic-gate print_rtmsg(rtm, rlen); 8017c478bd9Sstevel@tonic-gate } else { 8027c478bd9Sstevel@tonic-gate struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate (void) printf("%-20.20s ", 8057c478bd9Sstevel@tonic-gate rtm->rtm_flags & RTF_HOST ? routename(sa) : 8067c478bd9Sstevel@tonic-gate netname(sa)); 8077c478bd9Sstevel@tonic-gate /* LINTED */ 8087c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)(salen(sa) + (char *)sa); 8097c478bd9Sstevel@tonic-gate (void) printf("%-20.20s ", routename(sa)); 8107c478bd9Sstevel@tonic-gate (void) printf("done\n"); 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate /* 8157c478bd9Sstevel@tonic-gate * Return the name of the host whose address is given. 8167c478bd9Sstevel@tonic-gate */ 8177c478bd9Sstevel@tonic-gate char * 8187c478bd9Sstevel@tonic-gate routename(struct sockaddr *sa) 8197c478bd9Sstevel@tonic-gate { 8207c478bd9Sstevel@tonic-gate char *cp; 8217c478bd9Sstevel@tonic-gate static char line[MAXHOSTNAMELEN + 1]; 8227c478bd9Sstevel@tonic-gate struct hostent *hp = NULL; 8237c478bd9Sstevel@tonic-gate static char domain[MAXHOSTNAMELEN + 1]; 8247c478bd9Sstevel@tonic-gate static boolean_t first = B_TRUE; 8257c478bd9Sstevel@tonic-gate struct in_addr in; 8267c478bd9Sstevel@tonic-gate struct in6_addr in6; 8277c478bd9Sstevel@tonic-gate int error_num; 8287c478bd9Sstevel@tonic-gate ushort_t *s; 8297c478bd9Sstevel@tonic-gate ushort_t *slim; 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate if (first) { 8327c478bd9Sstevel@tonic-gate first = B_FALSE; 8337c478bd9Sstevel@tonic-gate if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 8347c478bd9Sstevel@tonic-gate (cp = strchr(domain, '.'))) 8357c478bd9Sstevel@tonic-gate (void) strcpy(domain, cp + 1); 8367c478bd9Sstevel@tonic-gate else 8377c478bd9Sstevel@tonic-gate domain[0] = 0; 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate if (salen(sa) == 0) { 8417c478bd9Sstevel@tonic-gate (void) strcpy(line, "default"); 8427c478bd9Sstevel@tonic-gate return (line); 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate case AF_INET: 8477c478bd9Sstevel@tonic-gate /* LINTED */ 8487c478bd9Sstevel@tonic-gate in = ((struct sockaddr_in *)sa)->sin_addr; 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate cp = NULL; 8517c478bd9Sstevel@tonic-gate if (in.s_addr == INADDR_ANY) 8527c478bd9Sstevel@tonic-gate cp = "default"; 8537c478bd9Sstevel@tonic-gate if (cp == NULL && !nflag) { 8547c478bd9Sstevel@tonic-gate hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 8557c478bd9Sstevel@tonic-gate AF_INET); 8567c478bd9Sstevel@tonic-gate if (hp != NULL) { 8577c478bd9Sstevel@tonic-gate if (((cp = strchr(hp->h_name, '.')) != NULL) && 8587c478bd9Sstevel@tonic-gate (strcmp(cp + 1, domain) == 0)) 8597c478bd9Sstevel@tonic-gate *cp = 0; 8607c478bd9Sstevel@tonic-gate cp = hp->h_name; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate if (cp != NULL) { 8647c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 8657c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 8667c478bd9Sstevel@tonic-gate } else { 8677c478bd9Sstevel@tonic-gate in.s_addr = ntohl(in.s_addr); 8687c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 8697c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8), 8707c478bd9Sstevel@tonic-gate C(in.s_addr)); 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate break; 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate case AF_LINK: 8757c478bd9Sstevel@tonic-gate return (link_ntoa((struct sockaddr_dl *)sa)); 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate case AF_INET6: 8787c478bd9Sstevel@tonic-gate /* LINTED */ 8797c478bd9Sstevel@tonic-gate in6 = ((struct sockaddr_in6 *)sa)->sin6_addr; 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate cp = NULL; 8827c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&in6)) 8837c478bd9Sstevel@tonic-gate cp = "default"; 8847c478bd9Sstevel@tonic-gate if (cp == NULL && !nflag) { 8857c478bd9Sstevel@tonic-gate hp = getipnodebyaddr((char *)&in6, 8867c478bd9Sstevel@tonic-gate sizeof (struct in6_addr), AF_INET6, &error_num); 8877c478bd9Sstevel@tonic-gate if (hp != NULL) { 8887c478bd9Sstevel@tonic-gate if (((cp = strchr(hp->h_name, '.')) != NULL) && 8897c478bd9Sstevel@tonic-gate (strcmp(cp + 1, domain) == 0)) 8907c478bd9Sstevel@tonic-gate *cp = 0; 8917c478bd9Sstevel@tonic-gate cp = hp->h_name; 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate if (cp != NULL) { 8957c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 8967c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 8977c478bd9Sstevel@tonic-gate } else { 8987c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&in6, line, 8997c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN); 9007c478bd9Sstevel@tonic-gate } 9017c478bd9Sstevel@tonic-gate if (hp != NULL) 9027c478bd9Sstevel@tonic-gate freehostent(hp); 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate break; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate default: 9077c478bd9Sstevel@tonic-gate s = (ushort_t *)sa; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate slim = s + ((salen(sa) + 1) >> 1); 9107c478bd9Sstevel@tonic-gate cp = line + sprintf(line, "(%d)", sa->sa_family); 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate while (++s < slim) /* start with sa->sa_data */ 9137c478bd9Sstevel@tonic-gate cp += sprintf(cp, " %x", *s); 9147c478bd9Sstevel@tonic-gate break; 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate return (line); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* 9207c478bd9Sstevel@tonic-gate * Return the name of the network whose address is given. 9217c478bd9Sstevel@tonic-gate * The address is assumed to be that of a net or subnet, not a host. 9227c478bd9Sstevel@tonic-gate */ 9237c478bd9Sstevel@tonic-gate static char * 9247c478bd9Sstevel@tonic-gate netname(struct sockaddr *sa) 9257c478bd9Sstevel@tonic-gate { 9267c478bd9Sstevel@tonic-gate char *cp = NULL; 9277c478bd9Sstevel@tonic-gate static char line[MAXHOSTNAMELEN + 1]; 9287c478bd9Sstevel@tonic-gate struct netent *np; 9297c478bd9Sstevel@tonic-gate in_addr_t net, mask; 9307c478bd9Sstevel@tonic-gate int subnetshift; 9317c478bd9Sstevel@tonic-gate struct in_addr in; 9327c478bd9Sstevel@tonic-gate ushort_t *s; 9337c478bd9Sstevel@tonic-gate ushort_t *slim; 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate case AF_INET: 9387c478bd9Sstevel@tonic-gate /* LINTED */ 9397c478bd9Sstevel@tonic-gate in = ((struct sockaddr_in *)sa)->sin_addr; 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate in.s_addr = ntohl(in.s_addr); 9427c478bd9Sstevel@tonic-gate if (in.s_addr == INADDR_ANY) { 9437c478bd9Sstevel@tonic-gate cp = "default"; 9447c478bd9Sstevel@tonic-gate } else if (!nflag) { 9457c478bd9Sstevel@tonic-gate if (IN_CLASSA(in.s_addr)) { 9467c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 9477c478bd9Sstevel@tonic-gate subnetshift = 8; 9487c478bd9Sstevel@tonic-gate } else if (IN_CLASSB(in.s_addr)) { 9497c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 9507c478bd9Sstevel@tonic-gate subnetshift = 8; 9517c478bd9Sstevel@tonic-gate } else { 9527c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 9537c478bd9Sstevel@tonic-gate subnetshift = 4; 9547c478bd9Sstevel@tonic-gate } 9557c478bd9Sstevel@tonic-gate /* 9567c478bd9Sstevel@tonic-gate * If there are more bits than the standard mask 9577c478bd9Sstevel@tonic-gate * would suggest, subnets must be in use. 9587c478bd9Sstevel@tonic-gate * Guess at the subnet mask, assuming reasonable 9597c478bd9Sstevel@tonic-gate * width subnet fields. 9607c478bd9Sstevel@tonic-gate */ 9617c478bd9Sstevel@tonic-gate while (in.s_addr &~ mask) 9627c478bd9Sstevel@tonic-gate mask = (long)mask >> subnetshift; 9637c478bd9Sstevel@tonic-gate net = in.s_addr & mask; 9647c478bd9Sstevel@tonic-gate while ((mask & 1) == 0) 9657c478bd9Sstevel@tonic-gate mask >>= 1, net >>= 1; 9667c478bd9Sstevel@tonic-gate np = getnetbyaddr(net, AF_INET); 9677c478bd9Sstevel@tonic-gate if (np != NULL) 9687c478bd9Sstevel@tonic-gate cp = np->n_name; 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate if (cp != NULL) { 9717c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 9727c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 9737c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xffffff) == 0) { 9747c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u", C(in.s_addr >> 24)); 9757c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xffff) == 0) { 9767c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 9777c478bd9Sstevel@tonic-gate C(in.s_addr >> 16)); 9787c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xff) == 0) { 9797c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 9807c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8)); 9817c478bd9Sstevel@tonic-gate } else { 9827c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 9837c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8), 9847c478bd9Sstevel@tonic-gate C(in.s_addr)); 9857c478bd9Sstevel@tonic-gate } 9867c478bd9Sstevel@tonic-gate break; 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate case AF_LINK: 9897c478bd9Sstevel@tonic-gate return (link_ntoa((struct sockaddr_dl *)sa)); 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate case AF_INET6: 9927c478bd9Sstevel@tonic-gate return (routename(sa)); 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate default: 9957c478bd9Sstevel@tonic-gate /* LINTED */ 9967c478bd9Sstevel@tonic-gate s = (ushort_t *)sa->sa_data; 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate slim = s + ((salen(sa) + 1) >> 1); 9997c478bd9Sstevel@tonic-gate cp = line + sprintf(line, "af %d:", sa->sa_family); 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate while (s < slim) 10027c478bd9Sstevel@tonic-gate cp += sprintf(cp, " %x", *s++); 10037c478bd9Sstevel@tonic-gate break; 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate return (line); 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate 1008*a59fa508Sjl138328 /* 1009*a59fa508Sjl138328 * Initialize a new structure. Keep in mind that ri_dst_str, ri_gate_str and 1010*a59fa508Sjl138328 * ri_ifp_str will be freed by det_rtcmd_irep, so they should either be NULL 1011*a59fa508Sjl138328 * or point to dynamically allocated memory. 1012*a59fa508Sjl138328 */ 1013*a59fa508Sjl138328 rtcmd_irep_t * 1014*a59fa508Sjl138328 new_rtcmd_irep(void) 1015*a59fa508Sjl138328 { 1016*a59fa508Sjl138328 rtcmd_irep_t *rcip; 1017*a59fa508Sjl138328 1018*a59fa508Sjl138328 rcip = calloc(1, sizeof (rtcmd_irep_t)); 1019*a59fa508Sjl138328 if (rcip == NULL) { 1020*a59fa508Sjl138328 quit("calloc", errno); 1021*a59fa508Sjl138328 } 1022*a59fa508Sjl138328 rcip->ri_af = af; 1023*a59fa508Sjl138328 rcip->ri_flags = RTF_STATIC; 1024*a59fa508Sjl138328 return (rcip); 1025*a59fa508Sjl138328 } 1026*a59fa508Sjl138328 10277c478bd9Sstevel@tonic-gate void 1028*a59fa508Sjl138328 del_rtcmd_irep(rtcmd_irep_t *rcip) 1029*a59fa508Sjl138328 { 1030*a59fa508Sjl138328 free(rcip->ri_dest_str); 1031*a59fa508Sjl138328 free(rcip->ri_gate_str); 1032*a59fa508Sjl138328 free(rcip->ri_ifp_str); 1033*a59fa508Sjl138328 if (rcip->ri_gate_hp != NULL) { 1034*a59fa508Sjl138328 freehostent(rcip->ri_gate_hp); 1035*a59fa508Sjl138328 } 1036*a59fa508Sjl138328 free(rcip); 1037*a59fa508Sjl138328 } 1038*a59fa508Sjl138328 1039*a59fa508Sjl138328 void 1040*a59fa508Sjl138328 save_string(char **dst, char *src) 1041*a59fa508Sjl138328 { 1042*a59fa508Sjl138328 free(*dst); 1043*a59fa508Sjl138328 *dst = strdup(src); 1044*a59fa508Sjl138328 if (*dst == NULL) { 1045*a59fa508Sjl138328 quit("malloc", errno); 1046*a59fa508Sjl138328 } 1047*a59fa508Sjl138328 } 1048*a59fa508Sjl138328 1049*a59fa508Sjl138328 /* 1050*a59fa508Sjl138328 * Print the short form summary of a route command. 1051*a59fa508Sjl138328 * Eg. "add net default: gateway 10.0.0.1" 1052*a59fa508Sjl138328 * The final newline is not added, allowing the caller to append additional 1053*a59fa508Sjl138328 * information. 1054*a59fa508Sjl138328 */ 1055*a59fa508Sjl138328 void 1056*a59fa508Sjl138328 print_rtcmd_short(FILE *to, rtcmd_irep_t *rcip, boolean_t gw_good, 1057*a59fa508Sjl138328 boolean_t to_saved) 1058*a59fa508Sjl138328 { 1059*a59fa508Sjl138328 char *cmd; 1060*a59fa508Sjl138328 char obuf[INET6_ADDRSTRLEN]; 1061*a59fa508Sjl138328 1062*a59fa508Sjl138328 switch (rcip->ri_cmd) { 1063*a59fa508Sjl138328 case RTM_ADD: 1064*a59fa508Sjl138328 cmd = "add"; 1065*a59fa508Sjl138328 break; 1066*a59fa508Sjl138328 case RTM_CHANGE: 1067*a59fa508Sjl138328 cmd = "change"; 1068*a59fa508Sjl138328 break; 1069*a59fa508Sjl138328 case RTM_DELETE: 1070*a59fa508Sjl138328 cmd = "delete"; 1071*a59fa508Sjl138328 break; 1072*a59fa508Sjl138328 case RTM_GET: 1073*a59fa508Sjl138328 cmd = "get"; 1074*a59fa508Sjl138328 break; 1075*a59fa508Sjl138328 default: 1076*a59fa508Sjl138328 assert(0); 1077*a59fa508Sjl138328 } 1078*a59fa508Sjl138328 1079*a59fa508Sjl138328 (void) fprintf(to, "%s%s %s %s", cmd, 1080*a59fa508Sjl138328 (to_saved) ? " persistent" : "", 1081*a59fa508Sjl138328 (rcip->ri_flags & RTF_HOST) ? "host" : "net", 1082*a59fa508Sjl138328 (rcip->ri_dest_str == NULL) ? "NULL" : rcip->ri_dest_str); 1083*a59fa508Sjl138328 1084*a59fa508Sjl138328 if (rcip->ri_gate_str != NULL) { 1085*a59fa508Sjl138328 switch (rcip->ri_af) { 1086*a59fa508Sjl138328 case AF_INET: 1087*a59fa508Sjl138328 if (nflag) { 1088*a59fa508Sjl138328 (void) fprintf(to, ": gateway %s", 1089*a59fa508Sjl138328 inet_ntoa(rcip->ri_gate.sin.sin_addr)); 1090*a59fa508Sjl138328 } else if (gw_good && 1091*a59fa508Sjl138328 rcip->ri_gate_hp != NULL && 1092*a59fa508Sjl138328 rcip->ri_gate_hp->h_addr_list[1] != NULL) { 1093*a59fa508Sjl138328 /* 1094*a59fa508Sjl138328 * Print the actual address used in the case 1095*a59fa508Sjl138328 * where there was more than one address 1096*a59fa508Sjl138328 * available for the name, and one was used 1097*a59fa508Sjl138328 * successfully. 1098*a59fa508Sjl138328 */ 1099*a59fa508Sjl138328 (void) fprintf(to, ": gateway %s (%s)", 1100*a59fa508Sjl138328 rcip->ri_gate_str, 1101*a59fa508Sjl138328 inet_ntoa(rcip->ri_gate.sin.sin_addr)); 1102*a59fa508Sjl138328 } else { 1103*a59fa508Sjl138328 (void) fprintf(to, ": gateway %s", 1104*a59fa508Sjl138328 rcip->ri_gate_str); 1105*a59fa508Sjl138328 } 1106*a59fa508Sjl138328 break; 1107*a59fa508Sjl138328 case AF_INET6: 1108*a59fa508Sjl138328 if (inet_ntop(AF_INET6, 1109*a59fa508Sjl138328 &rcip->ri_gate.sin6.sin6_addr, obuf, 1110*a59fa508Sjl138328 INET6_ADDRSTRLEN) != NULL) { 1111*a59fa508Sjl138328 if (nflag) { 1112*a59fa508Sjl138328 (void) fprintf(to, ": gateway %s", 1113*a59fa508Sjl138328 obuf); 1114*a59fa508Sjl138328 break; 1115*a59fa508Sjl138328 } 1116*a59fa508Sjl138328 if (gw_good && 1117*a59fa508Sjl138328 rcip->ri_gate_hp->h_addr_list[1] != NULL) { 1118*a59fa508Sjl138328 (void) fprintf(to, ": gateway %s (%s)", 1119*a59fa508Sjl138328 rcip->ri_gate_str, obuf); 1120*a59fa508Sjl138328 break; 1121*a59fa508Sjl138328 } 1122*a59fa508Sjl138328 } 1123*a59fa508Sjl138328 /* FALLTHROUGH */ 1124*a59fa508Sjl138328 default: 1125*a59fa508Sjl138328 (void) fprintf(to, ": gateway %s", 1126*a59fa508Sjl138328 rcip->ri_gate_str); 1127*a59fa508Sjl138328 break; 1128*a59fa508Sjl138328 } 1129*a59fa508Sjl138328 } 1130*a59fa508Sjl138328 } 1131*a59fa508Sjl138328 1132*a59fa508Sjl138328 void 1133*a59fa508Sjl138328 set_metric(rtcmd_irep_t *rcip, char *value, int key, boolean_t lock) 11347c478bd9Sstevel@tonic-gate { 11357c478bd9Sstevel@tonic-gate int flag = 0; 11367c478bd9Sstevel@tonic-gate uint_t noval, *valp = &noval; 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate switch (key) { 1139*a59fa508Sjl138328 #define caseof(x, y, z) \ 1140*a59fa508Sjl138328 case (x): valp = &(rcip->ri_metrics.z); flag = (y); break 1141*a59fa508Sjl138328 11427c478bd9Sstevel@tonic-gate caseof(K_MTU, RTV_MTU, rmx_mtu); 11437c478bd9Sstevel@tonic-gate caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 11447c478bd9Sstevel@tonic-gate caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 11457c478bd9Sstevel@tonic-gate caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 11467c478bd9Sstevel@tonic-gate caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 11477c478bd9Sstevel@tonic-gate caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 11487c478bd9Sstevel@tonic-gate caseof(K_RTT, RTV_RTT, rmx_rtt); 11497c478bd9Sstevel@tonic-gate caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 11507c478bd9Sstevel@tonic-gate #undef caseof 11517c478bd9Sstevel@tonic-gate } 1152*a59fa508Sjl138328 rcip->ri_inits |= flag; 1153*a59fa508Sjl138328 if (lock) 1154*a59fa508Sjl138328 rcip->ri_metrics.rmx_locks |= flag; 11557c478bd9Sstevel@tonic-gate *valp = atoi(value); 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate 1158*a59fa508Sjl138328 /* 1159*a59fa508Sjl138328 * Parse the options give in argv[], filling in rcip with the results. 1160*a59fa508Sjl138328 * If cmd_string is non-null, argc and argv are ignored, and cmd_string is 1161*a59fa508Sjl138328 * tokenized to produce the command line. Cmd_string is tokenized using 1162*a59fa508Sjl138328 * strtok, which will overwrite whitespace in the string with nulls. 1163*a59fa508Sjl138328 * 1164*a59fa508Sjl138328 * Returns B_TRUE on success and B_FALSE on failure. 1165*a59fa508Sjl138328 */ 1166*a59fa508Sjl138328 boolean_t 1167*a59fa508Sjl138328 args_to_rtcmd(rtcmd_irep_t *rcip, char **argv, char *cmd_string) 11687c478bd9Sstevel@tonic-gate { 1169*a59fa508Sjl138328 const char *ws = "\f\n\r\t\v "; 1170*a59fa508Sjl138328 char *tok = cmd_string; 1171*a59fa508Sjl138328 char *keyword_str; 1172*a59fa508Sjl138328 addr_type_t atype = ADDR_TYPE_ANY; 1173*a59fa508Sjl138328 boolean_t iflag = B_FALSE; 1174*a59fa508Sjl138328 boolean_t locknext = B_FALSE; 1175*a59fa508Sjl138328 boolean_t lockrest = B_FALSE; 1176*a59fa508Sjl138328 boolean_t dash_keyword; 11777c478bd9Sstevel@tonic-gate int key; 1178*a59fa508Sjl138328 char *err; 11797c478bd9Sstevel@tonic-gate 1180*a59fa508Sjl138328 if (cmd_string == NULL) { 1181*a59fa508Sjl138328 tok = argv[0]; 1182*a59fa508Sjl138328 } else { 1183*a59fa508Sjl138328 tok = strtok(cmd_string, ws); 11847c478bd9Sstevel@tonic-gate } 1185*a59fa508Sjl138328 1186*a59fa508Sjl138328 /* 1187*a59fa508Sjl138328 * The command keywords are already fully checked by main() or 1188*a59fa508Sjl138328 * search_rtfile(). 1189*a59fa508Sjl138328 */ 1190*a59fa508Sjl138328 switch (*tok) { 1191*a59fa508Sjl138328 case 'a': 1192*a59fa508Sjl138328 rcip->ri_cmd = RTM_ADD; 1193*a59fa508Sjl138328 break; 1194*a59fa508Sjl138328 case 'c': 1195*a59fa508Sjl138328 rcip->ri_cmd = RTM_CHANGE; 1196*a59fa508Sjl138328 break; 1197*a59fa508Sjl138328 case 'd': 1198*a59fa508Sjl138328 rcip->ri_cmd = RTM_DELETE; 1199*a59fa508Sjl138328 break; 1200*a59fa508Sjl138328 case 'g': 1201*a59fa508Sjl138328 rcip->ri_cmd = RTM_GET; 1202*a59fa508Sjl138328 break; 1203*a59fa508Sjl138328 default: 1204*a59fa508Sjl138328 /* NOTREACHED */ 1205*a59fa508Sjl138328 quit(gettext("Internal Error"), EINVAL); 1206*a59fa508Sjl138328 /* NOTREACHED */ 1207*a59fa508Sjl138328 } 1208*a59fa508Sjl138328 1209*a59fa508Sjl138328 #define NEXTTOKEN \ 1210*a59fa508Sjl138328 ((tok = (cmd_string == NULL ? *++argv : strtok(NULL, ws))) != NULL) 1211*a59fa508Sjl138328 1212*a59fa508Sjl138328 while (NEXTTOKEN) { 1213*a59fa508Sjl138328 keyword_str = tok; 1214*a59fa508Sjl138328 if (*tok == '-') { 1215*a59fa508Sjl138328 dash_keyword = B_TRUE; 1216*a59fa508Sjl138328 key = keyword(tok + 1); 1217*a59fa508Sjl138328 } else { 1218*a59fa508Sjl138328 dash_keyword = B_FALSE; 1219*a59fa508Sjl138328 key = keyword(tok); 1220*a59fa508Sjl138328 if (key != K_HOST && key != K_NET) { 1221*a59fa508Sjl138328 /* All others must be preceded by '-' */ 1222*a59fa508Sjl138328 key = 0; 1223*a59fa508Sjl138328 } 1224*a59fa508Sjl138328 } 1225*a59fa508Sjl138328 switch (key) { 1226*a59fa508Sjl138328 case K_HOST: 1227*a59fa508Sjl138328 if (atype == ADDR_TYPE_NET) { 1228*a59fa508Sjl138328 syntax_error(gettext("route: -host and -net " 1229*a59fa508Sjl138328 "are mutually exclusive\n")); 1230*a59fa508Sjl138328 return (B_FALSE); 1231*a59fa508Sjl138328 } 1232*a59fa508Sjl138328 atype = ADDR_TYPE_HOST; 1233*a59fa508Sjl138328 break; 1234*a59fa508Sjl138328 case K_NET: 1235*a59fa508Sjl138328 if (atype == ADDR_TYPE_HOST) { 1236*a59fa508Sjl138328 syntax_error(gettext("route: -host and -net " 1237*a59fa508Sjl138328 "are mutually exclusive\n")); 1238*a59fa508Sjl138328 return (B_FALSE); 1239*a59fa508Sjl138328 } 1240*a59fa508Sjl138328 atype = ADDR_TYPE_NET; 1241*a59fa508Sjl138328 break; 12427c478bd9Sstevel@tonic-gate case K_LINK: 1243*a59fa508Sjl138328 rcip->ri_af = AF_LINK; 12447c478bd9Sstevel@tonic-gate break; 12457c478bd9Sstevel@tonic-gate case K_INET: 1246*a59fa508Sjl138328 rcip->ri_af = AF_INET; 12477c478bd9Sstevel@tonic-gate break; 12487c478bd9Sstevel@tonic-gate case K_SA: 1249*a59fa508Sjl138328 rcip->ri_af = PF_ROUTE; 12507c478bd9Sstevel@tonic-gate break; 12517c478bd9Sstevel@tonic-gate case K_INET6: 1252*a59fa508Sjl138328 rcip->ri_af = AF_INET6; 12537c478bd9Sstevel@tonic-gate break; 12547c478bd9Sstevel@tonic-gate case K_IFACE: 12557c478bd9Sstevel@tonic-gate case K_INTERFACE: 12567c478bd9Sstevel@tonic-gate iflag = B_TRUE; 1257*a59fa508Sjl138328 /* fallthrough */ 12587c478bd9Sstevel@tonic-gate case K_NOSTATIC: 1259*a59fa508Sjl138328 rcip->ri_flags &= ~RTF_STATIC; 12607c478bd9Sstevel@tonic-gate break; 12617c478bd9Sstevel@tonic-gate case K_LOCK: 1262*a59fa508Sjl138328 locknext = B_TRUE; 12637c478bd9Sstevel@tonic-gate break; 12647c478bd9Sstevel@tonic-gate case K_LOCKREST: 12657c478bd9Sstevel@tonic-gate lockrest = B_TRUE; 12667c478bd9Sstevel@tonic-gate break; 12677c478bd9Sstevel@tonic-gate case K_REJECT: 1268*a59fa508Sjl138328 rcip->ri_flags |= RTF_REJECT; 12697c478bd9Sstevel@tonic-gate break; 12707c478bd9Sstevel@tonic-gate case K_BLACKHOLE: 1271*a59fa508Sjl138328 rcip->ri_flags |= RTF_BLACKHOLE; 12727c478bd9Sstevel@tonic-gate break; 12737c478bd9Sstevel@tonic-gate case K_PROTO1: 1274*a59fa508Sjl138328 rcip->ri_flags |= RTF_PROTO1; 12757c478bd9Sstevel@tonic-gate break; 12767c478bd9Sstevel@tonic-gate case K_PROTO2: 1277*a59fa508Sjl138328 rcip->ri_flags |= RTF_PROTO2; 12787c478bd9Sstevel@tonic-gate break; 12797c478bd9Sstevel@tonic-gate case K_CLONING: 1280*a59fa508Sjl138328 rcip->ri_flags |= RTF_CLONING; 12817c478bd9Sstevel@tonic-gate break; 12827c478bd9Sstevel@tonic-gate case K_XRESOLVE: 1283*a59fa508Sjl138328 rcip->ri_flags |= RTF_XRESOLVE; 12847c478bd9Sstevel@tonic-gate break; 12857c478bd9Sstevel@tonic-gate case K_STATIC: 1286*a59fa508Sjl138328 rcip->ri_flags |= RTF_STATIC; 12877c478bd9Sstevel@tonic-gate break; 12887c478bd9Sstevel@tonic-gate case K_IFA: 1289*a59fa508Sjl138328 if (!NEXTTOKEN) { 1290*a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1291*a59fa508Sjl138328 return (B_FALSE); 1292*a59fa508Sjl138328 } 1293*a59fa508Sjl138328 if (!getaddr(rcip, RTA_IFA, tok, atype)) { 1294*a59fa508Sjl138328 return (B_FALSE); 1295*a59fa508Sjl138328 } 12967c478bd9Sstevel@tonic-gate break; 12977c478bd9Sstevel@tonic-gate case K_IFP: 1298*a59fa508Sjl138328 if (!NEXTTOKEN) { 1299*a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1300*a59fa508Sjl138328 return (B_FALSE); 1301*a59fa508Sjl138328 } 1302*a59fa508Sjl138328 if (!getaddr(rcip, RTA_IFP, tok, atype)) { 1303*a59fa508Sjl138328 return (B_FALSE); 1304*a59fa508Sjl138328 } 13057c478bd9Sstevel@tonic-gate break; 13067c478bd9Sstevel@tonic-gate case K_GATEWAY: 1307*a59fa508Sjl138328 if (!NEXTTOKEN) { 1308*a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1309*a59fa508Sjl138328 return (B_FALSE); 1310*a59fa508Sjl138328 } 1311*a59fa508Sjl138328 if (!getaddr(rcip, RTA_GATEWAY, tok, atype)) { 1312*a59fa508Sjl138328 return (B_FALSE); 1313*a59fa508Sjl138328 } 13147c478bd9Sstevel@tonic-gate break; 13157c478bd9Sstevel@tonic-gate case K_DST: 1316*a59fa508Sjl138328 if (!NEXTTOKEN) { 1317*a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1318*a59fa508Sjl138328 return (B_FALSE); 1319*a59fa508Sjl138328 } 1320*a59fa508Sjl138328 if (!getaddr(rcip, RTA_DST, tok, atype)) { 1321*a59fa508Sjl138328 return (B_FALSE); 1322*a59fa508Sjl138328 } 13237c478bd9Sstevel@tonic-gate break; 13247c478bd9Sstevel@tonic-gate case K_NETMASK: 1325*a59fa508Sjl138328 if (!NEXTTOKEN) { 1326*a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1327*a59fa508Sjl138328 return (B_FALSE); 1328*a59fa508Sjl138328 } 1329*a59fa508Sjl138328 if (!getaddr(rcip, RTA_NETMASK, tok, atype)) { 1330*a59fa508Sjl138328 return (B_FALSE); 1331*a59fa508Sjl138328 } 1332*a59fa508Sjl138328 atype = ADDR_TYPE_NET; 13337c478bd9Sstevel@tonic-gate break; 13347c478bd9Sstevel@tonic-gate case K_MTU: 13357c478bd9Sstevel@tonic-gate case K_HOPCOUNT: 13367c478bd9Sstevel@tonic-gate case K_EXPIRE: 13377c478bd9Sstevel@tonic-gate case K_RECVPIPE: 13387c478bd9Sstevel@tonic-gate case K_SENDPIPE: 13397c478bd9Sstevel@tonic-gate case K_SSTHRESH: 13407c478bd9Sstevel@tonic-gate case K_RTT: 13417c478bd9Sstevel@tonic-gate case K_RTTVAR: 1342*a59fa508Sjl138328 if (!NEXTTOKEN) { 1343*a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1344*a59fa508Sjl138328 return (B_FALSE); 1345*a59fa508Sjl138328 } 1346*a59fa508Sjl138328 set_metric(rcip, tok, key, locknext || lockrest); 1347*a59fa508Sjl138328 locknext = B_FALSE; 13487c478bd9Sstevel@tonic-gate break; 13497c478bd9Sstevel@tonic-gate case K_PRIVATE: 1350*a59fa508Sjl138328 rcip->ri_flags |= RTF_PRIVATE; 13517c478bd9Sstevel@tonic-gate break; 13527c478bd9Sstevel@tonic-gate case K_MULTIRT: 1353*a59fa508Sjl138328 rcip->ri_flags |= RTF_MULTIRT; 13547c478bd9Sstevel@tonic-gate break; 13557c478bd9Sstevel@tonic-gate case K_SETSRC: 1356*a59fa508Sjl138328 if (!NEXTTOKEN) { 1357*a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1358*a59fa508Sjl138328 return (B_FALSE); 1359*a59fa508Sjl138328 } 1360*a59fa508Sjl138328 if (!getaddr(rcip, RTA_SRC, tok, atype)) { 1361*a59fa508Sjl138328 return (B_FALSE); 1362*a59fa508Sjl138328 } 1363*a59fa508Sjl138328 rcip->ri_flags |= RTF_SETSRC; 13647c478bd9Sstevel@tonic-gate break; 13657c478bd9Sstevel@tonic-gate default: 1366*a59fa508Sjl138328 if (dash_keyword) { 1367*a59fa508Sjl138328 syntax_bad_keyword(tok + 1); 1368*a59fa508Sjl138328 return (B_FALSE); 13697c478bd9Sstevel@tonic-gate } 1370*a59fa508Sjl138328 if ((rcip->ri_addrs & RTA_DST) == 0) { 1371*a59fa508Sjl138328 if (!getaddr(rcip, RTA_DST, tok, atype)) { 1372*a59fa508Sjl138328 return (B_FALSE); 1373*a59fa508Sjl138328 } 1374*a59fa508Sjl138328 } else if ((rcip->ri_addrs & RTA_GATEWAY) == 0) { 13757c478bd9Sstevel@tonic-gate /* 13767c478bd9Sstevel@tonic-gate * For the gateway parameter, retrieve the 13777c478bd9Sstevel@tonic-gate * pointer to the struct hostent so that all 13787c478bd9Sstevel@tonic-gate * possible addresses can be tried until one 13797c478bd9Sstevel@tonic-gate * is successful. 13807c478bd9Sstevel@tonic-gate */ 1381*a59fa508Sjl138328 if (!getaddr(rcip, RTA_GATEWAY, tok, atype)) { 1382*a59fa508Sjl138328 return (B_FALSE); 1383*a59fa508Sjl138328 } 13847c478bd9Sstevel@tonic-gate } else { 1385*a59fa508Sjl138328 ulong_t metric; 13867c478bd9Sstevel@tonic-gate /* 13877c478bd9Sstevel@tonic-gate * Assume that a regular number is a metric. 13887c478bd9Sstevel@tonic-gate * Needed for compatibility with old route 13897c478bd9Sstevel@tonic-gate * command syntax. 13907c478bd9Sstevel@tonic-gate */ 1391*a59fa508Sjl138328 errno = 0; 1392*a59fa508Sjl138328 metric = strtoul(tok, &err, 10); 1393*a59fa508Sjl138328 if (errno == 0 && *err == '\0' && 13947c478bd9Sstevel@tonic-gate metric < 0x80000000ul) { 13957c478bd9Sstevel@tonic-gate iflag = (metric == 0); 13967c478bd9Sstevel@tonic-gate if (verbose) { 13977c478bd9Sstevel@tonic-gate (void) printf("old usage of " 13987c478bd9Sstevel@tonic-gate "trailing number, assuming " 13997c478bd9Sstevel@tonic-gate "route %s\n", iflag ? 14007c478bd9Sstevel@tonic-gate "to if" : "via gateway"); 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate continue; 14037c478bd9Sstevel@tonic-gate } 1404*a59fa508Sjl138328 if (!getaddr(rcip, RTA_NETMASK, tok, atype)) { 1405*a59fa508Sjl138328 return (B_FALSE); 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate } 14087c478bd9Sstevel@tonic-gate } 1409*a59fa508Sjl138328 } 1410*a59fa508Sjl138328 #undef NEXTTOKEN 1411*a59fa508Sjl138328 1412*a59fa508Sjl138328 if ((rcip->ri_addrs & RTA_DST) == 0) { 1413*a59fa508Sjl138328 syntax_error(gettext("route: destination required\n")); 1414*a59fa508Sjl138328 return (B_FALSE); 1415*a59fa508Sjl138328 } else if ((rcip->ri_cmd == RTM_ADD || rcip->ri_cmd == RTM_DELETE) && 1416*a59fa508Sjl138328 (rcip->ri_addrs & RTA_GATEWAY) == 0) { 1417*a59fa508Sjl138328 syntax_error(gettext( 1418*a59fa508Sjl138328 "route: gateway required for add or delete command\n")); 1419*a59fa508Sjl138328 return (B_FALSE); 1420*a59fa508Sjl138328 } 1421*a59fa508Sjl138328 1422*a59fa508Sjl138328 if (!iflag) { 1423*a59fa508Sjl138328 rcip->ri_flags |= RTF_GATEWAY; 1424*a59fa508Sjl138328 } 1425*a59fa508Sjl138328 1426*a59fa508Sjl138328 if (atype != ADDR_TYPE_NET) { 1427*a59fa508Sjl138328 if (rcip->ri_addrs & RTA_NETMASK) { 1428*a59fa508Sjl138328 /* 1429*a59fa508Sjl138328 * We know the netmask, so we can set the host flag 1430*a59fa508Sjl138328 * based on whether the netmask is the host netmask. 1431*a59fa508Sjl138328 */ 1432*a59fa508Sjl138328 if (rcip->ri_af == AF_INET && 1433*a59fa508Sjl138328 rcip->ri_mask.sin.sin_addr.s_addr == 1434*a59fa508Sjl138328 IP_HOST_MASK) { 1435*a59fa508Sjl138328 rcip->ri_flags |= RTF_HOST; 1436*a59fa508Sjl138328 } 1437*a59fa508Sjl138328 if (rcip->ri_af == AF_INET6 && 1438*a59fa508Sjl138328 memcmp(&rcip->ri_mask.sin6.sin6_addr, 1439*a59fa508Sjl138328 &in6_host_mask, 1440*a59fa508Sjl138328 sizeof (struct in6_addr)) == 0) { 1441*a59fa508Sjl138328 rcip->ri_flags |= RTF_HOST; 1442*a59fa508Sjl138328 } 1443*a59fa508Sjl138328 } else { 1444*a59fa508Sjl138328 /* 1445*a59fa508Sjl138328 * If no prefix mask has been saved at this point, it 1446*a59fa508Sjl138328 * only makes sense to treat the destination address 1447*a59fa508Sjl138328 * as a host address. 1448*a59fa508Sjl138328 */ 1449*a59fa508Sjl138328 rcip->ri_flags |= RTF_HOST; 1450*a59fa508Sjl138328 } 1451*a59fa508Sjl138328 } 1452*a59fa508Sjl138328 return (B_TRUE); 14533f33f4f7Sjl138328 } 14547a23074eSdduvall 14557a23074eSdduvall /* 1456*a59fa508Sjl138328 * This command always seeks to the end of the file prior to writing. 14577a23074eSdduvall */ 1458*a59fa508Sjl138328 void 1459*a59fa508Sjl138328 write_to_rtfile(FILE *fp, int argc, char **argv) 1460*a59fa508Sjl138328 { 1461*a59fa508Sjl138328 char file_line[BUF_SIZE]; 1462*a59fa508Sjl138328 int len; 1463*a59fa508Sjl138328 int i; 1464*a59fa508Sjl138328 1465*a59fa508Sjl138328 len = 0; 1466*a59fa508Sjl138328 if (early_v6_keyword) { 1467*a59fa508Sjl138328 /* 1468*a59fa508Sjl138328 * This flag is set when "inet6" was seen as an 1469*a59fa508Sjl138328 * argument to the -f flag. Normally, when writing 1470*a59fa508Sjl138328 * routes to the persistent route file, everything on 1471*a59fa508Sjl138328 * the command line after "add" is saved verbatim. 1472*a59fa508Sjl138328 * In this case, the arguments after "add" may not be 1473*a59fa508Sjl138328 * sufficient, as the ipv6 keyword came before "add", 1474*a59fa508Sjl138328 * yet must be present in the persistent route file. 1475*a59fa508Sjl138328 */ 1476*a59fa508Sjl138328 len += snprintf(file_line, BUF_SIZE, "-inet6 "); 14773f33f4f7Sjl138328 } 1478*a59fa508Sjl138328 for (i = 0; argc > 0 && len < BUF_SIZE; i++, argc--) { 1479*a59fa508Sjl138328 len += snprintf(&file_line[len], BUF_SIZE - len, "%s ", 1480*a59fa508Sjl138328 argv[i]); 1481*a59fa508Sjl138328 } 1482*a59fa508Sjl138328 if (len >= BUF_SIZE) 1483*a59fa508Sjl138328 quit(gettext("Internal Error"), EINVAL); 1484*a59fa508Sjl138328 file_line[len - 1] = '\n'; 1485*a59fa508Sjl138328 if (fseek(fp, 0, SEEK_END) != 0 || 1486*a59fa508Sjl138328 fputs(file_line, fp) == EOF) { 1487*a59fa508Sjl138328 quit(gettext("failed to write to route file"), 1488*a59fa508Sjl138328 errno); 1489*a59fa508Sjl138328 } 1490*a59fa508Sjl138328 } 1491*a59fa508Sjl138328 1492*a59fa508Sjl138328 boolean_t 1493*a59fa508Sjl138328 compare_rtcmd(rtcmd_irep_t *srch_rt, rtcmd_irep_t *file_rt) 1494*a59fa508Sjl138328 { 1495*a59fa508Sjl138328 if (strcmp(srch_rt->ri_dest_str, file_rt->ri_dest_str) != 0 || 1496*a59fa508Sjl138328 memcmp(&srch_rt->ri_mask, &file_rt->ri_mask, sizeof (su_t)) != 0) { 1497*a59fa508Sjl138328 return (B_FALSE); 1498*a59fa508Sjl138328 } 1499*a59fa508Sjl138328 return (srch_rt->ri_gate_str == NULL || 1500*a59fa508Sjl138328 strcmp(srch_rt->ri_gate_str, file_rt->ri_gate_str) == 0); 1501*a59fa508Sjl138328 } 1502*a59fa508Sjl138328 1503*a59fa508Sjl138328 /* 1504*a59fa508Sjl138328 * Search the route file for routes matching the supplied route. There are 3 1505*a59fa508Sjl138328 * modes of operation: 1506*a59fa508Sjl138328 * SEARCH_MODE_RET - no side effects. 1507*a59fa508Sjl138328 * SEARCH_MODE_PRINT - prints each matching line. 1508*a59fa508Sjl138328 * SEARCH_MODE_DEL - copies all valid, non-matching lines to tmp_fp. 1509*a59fa508Sjl138328 * 1510*a59fa508Sjl138328 * In all cases, the number of matches is returned. If rt is NULL, all routes 1511*a59fa508Sjl138328 * matching the global af value are considered matching. 1512*a59fa508Sjl138328 */ 1513*a59fa508Sjl138328 int 1514*a59fa508Sjl138328 search_rtfile(FILE *fp, FILE *temp_fp, rtcmd_irep_t *rt, search_mode_t mode) 1515*a59fa508Sjl138328 { 1516*a59fa508Sjl138328 char *tmp_buf; 1517*a59fa508Sjl138328 int match_cnt; 1518*a59fa508Sjl138328 boolean_t match; 1519*a59fa508Sjl138328 char file_line[BUF_SIZE + 4] = "add "; 1520*a59fa508Sjl138328 rtcmd_irep_t *thisrt; 1521*a59fa508Sjl138328 1522*a59fa508Sjl138328 match_cnt = 0; 1523*a59fa508Sjl138328 1524*a59fa508Sjl138328 /* 1525*a59fa508Sjl138328 * Leave space at the beginning of file_line for "add ". 1526*a59fa508Sjl138328 */ 1527*a59fa508Sjl138328 while (fgets(file_line + 4, BUF_SIZE, fp) != NULL) { 1528*a59fa508Sjl138328 1529*a59fa508Sjl138328 if (file_line[4] == '#' || file_line[4] == '\n') { 1530*a59fa508Sjl138328 /* Handle comments and blank lines */ 1531*a59fa508Sjl138328 if (mode == SEARCH_MODE_DEL && 1532*a59fa508Sjl138328 fputs(file_line + 4, temp_fp) == EOF) { 1533*a59fa508Sjl138328 quit(gettext( 1534*a59fa508Sjl138328 "route: failed to write to temp file"), 1535*a59fa508Sjl138328 errno); 1536*a59fa508Sjl138328 } 1537*a59fa508Sjl138328 continue; 1538*a59fa508Sjl138328 } 1539*a59fa508Sjl138328 thisrt = new_rtcmd_irep(); 1540*a59fa508Sjl138328 /* 1541*a59fa508Sjl138328 * thisrt->ri_af defaults to whatever address family happens 1542*a59fa508Sjl138328 * to be set in the global af, but routes in the persistent 1543*a59fa508Sjl138328 * route file must be treated as AF_INET by default. 1544*a59fa508Sjl138328 */ 1545*a59fa508Sjl138328 thisrt->ri_af = AF_INET; 1546*a59fa508Sjl138328 1547*a59fa508Sjl138328 exit_on_error = B_FALSE; 1548*a59fa508Sjl138328 tmp_buf = strdup(file_line); 1549*a59fa508Sjl138328 /* args_to_rtcmd() will mangle the string passed. */ 1550*a59fa508Sjl138328 if (!args_to_rtcmd(thisrt, NULL, tmp_buf)) { 1551*a59fa508Sjl138328 /* There was an error in args_to_rtcmd() or helpers */ 1552*a59fa508Sjl138328 del_rtcmd_irep(thisrt); 1553*a59fa508Sjl138328 free(tmp_buf); 1554*a59fa508Sjl138328 continue; 1555*a59fa508Sjl138328 } 1556*a59fa508Sjl138328 exit_on_error = B_TRUE; 1557*a59fa508Sjl138328 free(tmp_buf); 1558*a59fa508Sjl138328 1559*a59fa508Sjl138328 if (thisrt->ri_gate_str == NULL) { 1560*a59fa508Sjl138328 del_rtcmd_irep(thisrt); 1561*a59fa508Sjl138328 continue; 1562*a59fa508Sjl138328 } 1563*a59fa508Sjl138328 match = (rt == NULL) ? (thisrt->ri_af == af) : 1564*a59fa508Sjl138328 compare_rtcmd(rt, thisrt); 1565*a59fa508Sjl138328 1566*a59fa508Sjl138328 if (match) match_cnt++; 1567*a59fa508Sjl138328 if (match && mode == SEARCH_MODE_PRINT) { 1568*a59fa508Sjl138328 (void) printf("persistent: route %s", file_line); 1569*a59fa508Sjl138328 } 1570*a59fa508Sjl138328 if (match && mode == SEARCH_MODE_DEL) { 1571*a59fa508Sjl138328 thisrt->ri_cmd = RTM_DELETE; 1572*a59fa508Sjl138328 print_rtcmd_short(stdout, thisrt, B_FALSE, B_TRUE); 1573*a59fa508Sjl138328 (void) printf("\n"); 1574*a59fa508Sjl138328 } 1575*a59fa508Sjl138328 del_rtcmd_irep(thisrt); 1576*a59fa508Sjl138328 1577*a59fa508Sjl138328 if (!match && mode == SEARCH_MODE_DEL && 1578*a59fa508Sjl138328 fputs(file_line + 4, temp_fp) == EOF) { 1579*a59fa508Sjl138328 quit(gettext("failed to write to temp file"), 1580*a59fa508Sjl138328 errno); 1581*a59fa508Sjl138328 } 1582*a59fa508Sjl138328 } 1583*a59fa508Sjl138328 return (match_cnt); 1584*a59fa508Sjl138328 } 1585*a59fa508Sjl138328 1586*a59fa508Sjl138328 /* 1587*a59fa508Sjl138328 * Perform the route operation given in argv on the persistent route file. 1588*a59fa508Sjl138328 * If do_flush is set, the persistent route file is flushed of all routes 1589*a59fa508Sjl138328 * matching the global family, and the arguments are ignored. 1590*a59fa508Sjl138328 */ 1591*a59fa508Sjl138328 void 1592*a59fa508Sjl138328 save_route(int argc, char **argv, int do_flush) 1593*a59fa508Sjl138328 { 1594*a59fa508Sjl138328 rtcmd_irep_t *rt; 1595*a59fa508Sjl138328 int perm_fd; 1596*a59fa508Sjl138328 FILE *perm_fp; 1597*a59fa508Sjl138328 FILE *temp_fp; 1598*a59fa508Sjl138328 mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 1599*a59fa508Sjl138328 struct flock lock; 1600*a59fa508Sjl138328 struct stat st; 1601*a59fa508Sjl138328 const char commentstr[] = 1602*a59fa508Sjl138328 "# File generated by route(1M) - do not edit.\n"; 1603*a59fa508Sjl138328 1604*a59fa508Sjl138328 perm_fd = open(perm_file, O_RDWR | O_CREAT, fmode); 1605*a59fa508Sjl138328 if (perm_fd == -1 || fstat(perm_fd, &st) == -1) 1606*a59fa508Sjl138328 quit("failed to open route file", errno); 1607*a59fa508Sjl138328 1608*a59fa508Sjl138328 lock.l_type = F_WRLCK; 1609*a59fa508Sjl138328 lock.l_whence = SEEK_SET; 1610*a59fa508Sjl138328 lock.l_start = 0; 1611*a59fa508Sjl138328 lock.l_len = 0; 1612*a59fa508Sjl138328 if (fcntl(perm_fd, F_SETLK, &lock) != 0) { 1613*a59fa508Sjl138328 quit(gettext("failed to lock route file"), errno); 1614*a59fa508Sjl138328 /* NOTREACHED */ 1615*a59fa508Sjl138328 } 1616*a59fa508Sjl138328 if (st.st_size == 0 && 1617*a59fa508Sjl138328 write(perm_fd, commentstr, sizeof (commentstr) - 1) != 1618*a59fa508Sjl138328 sizeof (commentstr) - 1) 1619*a59fa508Sjl138328 quit(gettext("failed to open route file"), errno); 1620*a59fa508Sjl138328 1621*a59fa508Sjl138328 if ((perm_fp = fdopen(perm_fd, "r+")) == NULL) { 1622*a59fa508Sjl138328 quit(gettext("failed to open route file"), errno); 1623*a59fa508Sjl138328 /* NOTREACHED */ 1624*a59fa508Sjl138328 } 1625*a59fa508Sjl138328 1626*a59fa508Sjl138328 if (!do_flush) { 1627*a59fa508Sjl138328 rt = new_rtcmd_irep(); 1628*a59fa508Sjl138328 (void) args_to_rtcmd(rt, argv, NULL); 1629*a59fa508Sjl138328 } 1630*a59fa508Sjl138328 if (do_flush || rt->ri_cmd == RTM_DELETE) { 1631*a59fa508Sjl138328 if ((temp_fp = fopen(temp_file, "w")) == NULL) { 1632*a59fa508Sjl138328 quit(gettext("failed to open temp file"), errno); 1633*a59fa508Sjl138328 /* NOTREACHED */ 1634*a59fa508Sjl138328 } 1635*a59fa508Sjl138328 } 1636*a59fa508Sjl138328 if (do_flush) { 1637*a59fa508Sjl138328 (void) search_rtfile(perm_fp, temp_fp, NULL, SEARCH_MODE_DEL); 1638*a59fa508Sjl138328 if (fclose(temp_fp) != 0 || rename(temp_file, perm_file) != 0) { 1639*a59fa508Sjl138328 quit(gettext("failed to update route file"), errno); 1640*a59fa508Sjl138328 /* NOTREACHED */ 1641*a59fa508Sjl138328 } 1642*a59fa508Sjl138328 (void) fclose(perm_fp); 1643*a59fa508Sjl138328 return; 1644*a59fa508Sjl138328 } 1645*a59fa508Sjl138328 1646*a59fa508Sjl138328 switch (rt->ri_cmd) { 1647*a59fa508Sjl138328 case RTM_ADD: 1648*a59fa508Sjl138328 if (search_rtfile(perm_fp, NULL, rt, SEARCH_MODE_NULL) > 0) { 1649*a59fa508Sjl138328 /* Route is already in the file */ 1650*a59fa508Sjl138328 print_rtcmd_short(stderr, rt, B_FALSE, B_TRUE); 1651*a59fa508Sjl138328 (void) fprintf(stderr, ": entry exists\n"); 1652*a59fa508Sjl138328 exit(1); 1653*a59fa508Sjl138328 } 1654*a59fa508Sjl138328 write_to_rtfile(perm_fp, argc - 1, argv + 1); 1655*a59fa508Sjl138328 print_rtcmd_short(stdout, rt, B_FALSE, B_TRUE); 1656*a59fa508Sjl138328 (void) printf("\n"); 1657*a59fa508Sjl138328 break; 1658*a59fa508Sjl138328 1659*a59fa508Sjl138328 case RTM_CHANGE: 1660*a59fa508Sjl138328 syntax_error( 1661*a59fa508Sjl138328 gettext("route: change command not supported with -p\n")); 1662*a59fa508Sjl138328 /* NOTREACHED */ 1663*a59fa508Sjl138328 1664*a59fa508Sjl138328 case RTM_DELETE: 1665*a59fa508Sjl138328 if (search_rtfile(perm_fp, temp_fp, rt, SEARCH_MODE_DEL) <= 0) { 1666*a59fa508Sjl138328 /* Route not found */ 1667*a59fa508Sjl138328 print_rtcmd_short(stderr, rt, B_FALSE, B_TRUE); 1668*a59fa508Sjl138328 (void) fprintf(stderr, gettext(": not in file\n")); 1669*a59fa508Sjl138328 exit(1); 1670*a59fa508Sjl138328 } 1671*a59fa508Sjl138328 if (fclose(temp_fp) != 0 || rename(temp_file, perm_file) != 0) { 1672*a59fa508Sjl138328 quit(gettext("failed to update route file"), errno); 1673*a59fa508Sjl138328 /* NOTREACHED */ 1674*a59fa508Sjl138328 } 1675*a59fa508Sjl138328 break; 1676*a59fa508Sjl138328 1677*a59fa508Sjl138328 case RTM_GET: 1678*a59fa508Sjl138328 if (search_rtfile(perm_fp, temp_fp, rt, SEARCH_MODE_PRINT) <= 1679*a59fa508Sjl138328 0) { 1680*a59fa508Sjl138328 print_rtcmd_short(stdout, rt, B_FALSE, B_TRUE); 1681*a59fa508Sjl138328 (void) printf(gettext(": not in file\n")); 1682*a59fa508Sjl138328 } 1683*a59fa508Sjl138328 break; 1684*a59fa508Sjl138328 1685*a59fa508Sjl138328 default: 1686*a59fa508Sjl138328 quit(gettext("Internal Error"), EINVAL); 1687*a59fa508Sjl138328 /* NOTREACHED */ 1688*a59fa508Sjl138328 } 1689*a59fa508Sjl138328 1690*a59fa508Sjl138328 /* 1691*a59fa508Sjl138328 * Closing the file unlocks it. 1692*a59fa508Sjl138328 */ 1693*a59fa508Sjl138328 (void) fclose(perm_fp); 1694*a59fa508Sjl138328 } 1695*a59fa508Sjl138328 1696*a59fa508Sjl138328 int 1697*a59fa508Sjl138328 show_saved_routes(int argc) 1698*a59fa508Sjl138328 { 1699*a59fa508Sjl138328 int perm_fd; 1700*a59fa508Sjl138328 FILE *perm_fp; 1701*a59fa508Sjl138328 struct flock lock; 1702*a59fa508Sjl138328 int count = 0; 1703*a59fa508Sjl138328 1704*a59fa508Sjl138328 if (argc != 1) { 1705*a59fa508Sjl138328 syntax_error(gettext("route: invalid arguments for show\n")); 1706*a59fa508Sjl138328 } 1707*a59fa508Sjl138328 1708*a59fa508Sjl138328 perm_fd = open(perm_file, O_RDONLY, 0); 1709*a59fa508Sjl138328 1710*a59fa508Sjl138328 if (perm_fd == -1) { 1711*a59fa508Sjl138328 if (errno == ENOENT) { 1712*a59fa508Sjl138328 (void) printf("No persistent routes are defined\n"); 1713*a59fa508Sjl138328 return (0); 1714*a59fa508Sjl138328 } else { 1715*a59fa508Sjl138328 quit(gettext("failed to open route file"), errno); 1716*a59fa508Sjl138328 } 1717*a59fa508Sjl138328 } 1718*a59fa508Sjl138328 lock.l_type = F_RDLCK; 1719*a59fa508Sjl138328 lock.l_whence = SEEK_SET; 1720*a59fa508Sjl138328 lock.l_start = 0; 1721*a59fa508Sjl138328 lock.l_len = 0; 1722*a59fa508Sjl138328 if (fcntl(perm_fd, F_SETLK, &lock) != 0) { 1723*a59fa508Sjl138328 quit(gettext("failed to lock route file"), 1724*a59fa508Sjl138328 errno); 1725*a59fa508Sjl138328 /* NOTREACHED */ 1726*a59fa508Sjl138328 } 1727*a59fa508Sjl138328 if ((perm_fp = fdopen(perm_fd, "r")) == NULL) { 1728*a59fa508Sjl138328 quit(gettext("failed to open route file"), errno); 1729*a59fa508Sjl138328 /* NOTREACHED */ 1730*a59fa508Sjl138328 } 1731*a59fa508Sjl138328 count += search_rtfile(perm_fp, NULL, NULL, SEARCH_MODE_PRINT); 1732*a59fa508Sjl138328 (void) fseek(perm_fp, 0, SEEK_SET); 1733*a59fa508Sjl138328 af = AF_INET6; 1734*a59fa508Sjl138328 count += search_rtfile(perm_fp, NULL, NULL, SEARCH_MODE_PRINT); 1735*a59fa508Sjl138328 1736*a59fa508Sjl138328 if (count == 0) 1737*a59fa508Sjl138328 (void) printf("No persistent routes are defined\n"); 1738*a59fa508Sjl138328 1739*a59fa508Sjl138328 (void) fclose(perm_fp); 1740*a59fa508Sjl138328 return (0); 1741*a59fa508Sjl138328 } 1742*a59fa508Sjl138328 1743*a59fa508Sjl138328 int 1744*a59fa508Sjl138328 newroute(char **argv) 1745*a59fa508Sjl138328 { 1746*a59fa508Sjl138328 rtcmd_irep_t *newrt; 1747*a59fa508Sjl138328 int ret, attempts, oerrno; 1748*a59fa508Sjl138328 char *err; 1749*a59fa508Sjl138328 char obuf[INET6_ADDRSTRLEN]; 1750*a59fa508Sjl138328 #define hp (newrt->ri_gate_hp) 1751*a59fa508Sjl138328 1752*a59fa508Sjl138328 newrt = new_rtcmd_irep(); 1753*a59fa508Sjl138328 (void) args_to_rtcmd(newrt, argv, NULL); 1754*a59fa508Sjl138328 1755*a59fa508Sjl138328 if (newrt->ri_cmd != RTM_GET && !tflag) { 1756*a59fa508Sjl138328 /* Don't want to read back our messages */ 1757*a59fa508Sjl138328 (void) shutdown(s, 0); 1758*a59fa508Sjl138328 } 1759*a59fa508Sjl138328 if (newrt->ri_addrs & RTA_IFP) { 1760*a59fa508Sjl138328 newrt->ri_ifp.sdl.sdl_index = if_nametoindex(newrt->ri_ifp_str); 1761*a59fa508Sjl138328 if (newrt->ri_ifp.sdl.sdl_index == 0) { 1762*a59fa508Sjl138328 if (errno != ENXIO) { 1763*a59fa508Sjl138328 quit("if_nametoindex", errno); 1764*a59fa508Sjl138328 } else { 1765*a59fa508Sjl138328 (void) fprintf(stderr, 1766*a59fa508Sjl138328 gettext("route: %s: no such interface\n"), 1767*a59fa508Sjl138328 newrt->ri_ifp_str); 1768*a59fa508Sjl138328 exit(1); 1769*a59fa508Sjl138328 } 1770*a59fa508Sjl138328 } 1771*a59fa508Sjl138328 newrt->ri_ifp.sdl.sdl_family = AF_LINK; 1772*a59fa508Sjl138328 } 17737c478bd9Sstevel@tonic-gate for (attempts = 1; ; attempts++) { 17747c478bd9Sstevel@tonic-gate errno = 0; 1775*a59fa508Sjl138328 if ((ret = rtmsg(newrt)) == 0) 17767c478bd9Sstevel@tonic-gate break; 17777c478bd9Sstevel@tonic-gate if (errno != ENETUNREACH && errno != ESRCH) 17787c478bd9Sstevel@tonic-gate break; 1779*a59fa508Sjl138328 if ((newrt->ri_addrs & RTA_GATEWAY) && hp != NULL && 17807c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts] != NULL) { 17817c478bd9Sstevel@tonic-gate switch (af) { 17827c478bd9Sstevel@tonic-gate case AF_INET: 1783*a59fa508Sjl138328 (void) memmove(&newrt->ri_gate.sin.sin_addr, 17847c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts], hp->h_length); 17857c478bd9Sstevel@tonic-gate continue; 17867c478bd9Sstevel@tonic-gate case AF_INET6: 1787*a59fa508Sjl138328 (void) memmove(&newrt->ri_gate.sin6.sin6_addr, 17887c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts], hp->h_length); 17897c478bd9Sstevel@tonic-gate continue; 17907c478bd9Sstevel@tonic-gate } 17917c478bd9Sstevel@tonic-gate } 17927c478bd9Sstevel@tonic-gate break; 17937c478bd9Sstevel@tonic-gate } 17947c478bd9Sstevel@tonic-gate oerrno = errno; 1795*a59fa508Sjl138328 1796*a59fa508Sjl138328 if (newrt->ri_cmd != RTM_GET) { 1797*a59fa508Sjl138328 print_rtcmd_short(stdout, newrt, (ret == 0), B_FALSE); 17987a23074eSdduvall if (ret == 0) 17997a23074eSdduvall (void) printf("\n"); 1800*a59fa508Sjl138328 } else if (ret != 0) { 1801*a59fa508Sjl138328 /* 1802*a59fa508Sjl138328 * Note: there is nothing additional to print for get 1803*a59fa508Sjl138328 * if ret == 0. 1804*a59fa508Sjl138328 */ 18057a23074eSdduvall if (nflag) { 1806*a59fa508Sjl138328 switch (newrt->ri_af) { 18077a23074eSdduvall case AF_INET: 18087a23074eSdduvall (void) printf(" %s", 1809*a59fa508Sjl138328 inet_ntoa(newrt->ri_dst.sin.sin_addr)); 18107a23074eSdduvall break; 18117a23074eSdduvall case AF_INET6: 18127a23074eSdduvall if (inet_ntop(AF_INET6, 1813*a59fa508Sjl138328 (void *)&newrt->ri_dst.sin6.sin6_addr, 18147c478bd9Sstevel@tonic-gate obuf, INET6_ADDRSTRLEN) != NULL) { 18157c478bd9Sstevel@tonic-gate (void) printf(" %s", obuf); 18167c478bd9Sstevel@tonic-gate break; 18177c478bd9Sstevel@tonic-gate } 18187c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 18197c478bd9Sstevel@tonic-gate default: 1820*a59fa508Sjl138328 (void) printf("%s", newrt->ri_dest_str); 18217c478bd9Sstevel@tonic-gate break; 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate } else { 1824*a59fa508Sjl138328 (void) printf("%s", newrt->ri_dest_str); 18257c478bd9Sstevel@tonic-gate } 18267c478bd9Sstevel@tonic-gate } 1827*a59fa508Sjl138328 1828*a59fa508Sjl138328 if (ret != 0) { 18297c478bd9Sstevel@tonic-gate switch (oerrno) { 18307c478bd9Sstevel@tonic-gate case ESRCH: 18317c478bd9Sstevel@tonic-gate err = "not in table"; 18327c478bd9Sstevel@tonic-gate break; 18337c478bd9Sstevel@tonic-gate case EBUSY: 18347c478bd9Sstevel@tonic-gate err = "entry in use"; 18357c478bd9Sstevel@tonic-gate break; 18367c478bd9Sstevel@tonic-gate case ENOBUFS: 18377c478bd9Sstevel@tonic-gate err = "routing table overflow"; 18387c478bd9Sstevel@tonic-gate break; 18397c478bd9Sstevel@tonic-gate case EEXIST: 18407c478bd9Sstevel@tonic-gate err = "entry exists"; 18417c478bd9Sstevel@tonic-gate break; 18427c478bd9Sstevel@tonic-gate case EPERM: 18437c478bd9Sstevel@tonic-gate err = "insufficient privileges"; 18447c478bd9Sstevel@tonic-gate break; 18457c478bd9Sstevel@tonic-gate default: 18467c478bd9Sstevel@tonic-gate err = strerror(oerrno); 18477c478bd9Sstevel@tonic-gate break; 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate (void) printf(": %s\n", err); 18507c478bd9Sstevel@tonic-gate } 1851*a59fa508Sjl138328 1852*a59fa508Sjl138328 del_rtcmd_irep(newrt); 18537c478bd9Sstevel@tonic-gate 18547c478bd9Sstevel@tonic-gate return (oerrno); 1855*a59fa508Sjl138328 #undef hp 18567c478bd9Sstevel@tonic-gate } 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate /* 18607c478bd9Sstevel@tonic-gate * Convert a network number to the corresponding IP address. 18617c478bd9Sstevel@tonic-gate * If the RTA_NETMASK hasn't been specified yet set it based 18627c478bd9Sstevel@tonic-gate * on the class of address. 18637c478bd9Sstevel@tonic-gate */ 18647c478bd9Sstevel@tonic-gate static void 1865*a59fa508Sjl138328 inet_makenetandmask(rtcmd_irep_t *rcip, in_addr_t net, struct sockaddr_in *sin) 18667c478bd9Sstevel@tonic-gate { 18677c478bd9Sstevel@tonic-gate in_addr_t addr, mask; 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate if (net == 0) { 18707c478bd9Sstevel@tonic-gate mask = addr = 0; 18717c478bd9Sstevel@tonic-gate } else if (net < 128) { 18727c478bd9Sstevel@tonic-gate addr = net << IN_CLASSA_NSHIFT; 18737c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 18747c478bd9Sstevel@tonic-gate } else if (net < 65536) { 18757c478bd9Sstevel@tonic-gate addr = net << IN_CLASSB_NSHIFT; 18767c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 18777c478bd9Sstevel@tonic-gate } else if (net < 16777216L) { 18787c478bd9Sstevel@tonic-gate addr = net << IN_CLASSC_NSHIFT; 18797c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 18807c478bd9Sstevel@tonic-gate } else { 18817c478bd9Sstevel@tonic-gate addr = net; 18827c478bd9Sstevel@tonic-gate if ((addr & IN_CLASSA_HOST) == 0) 18837c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 18847c478bd9Sstevel@tonic-gate else if ((addr & IN_CLASSB_HOST) == 0) 18857c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 18867c478bd9Sstevel@tonic-gate else if ((addr & IN_CLASSC_HOST) == 0) 18877c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 18887c478bd9Sstevel@tonic-gate else { 18897c478bd9Sstevel@tonic-gate if (IN_CLASSA(addr)) 18907c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 18917c478bd9Sstevel@tonic-gate else if (IN_CLASSB(addr)) 18927c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 18937c478bd9Sstevel@tonic-gate else if (IN_CLASSC(addr)) 18947c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 18957c478bd9Sstevel@tonic-gate else 18967c478bd9Sstevel@tonic-gate mask = IP_HOST_MASK; 18977c478bd9Sstevel@tonic-gate mask = inet_makesubnetmask(addr, mask); 18987c478bd9Sstevel@tonic-gate } 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(addr); 19017c478bd9Sstevel@tonic-gate 1902*a59fa508Sjl138328 if (!(rcip->ri_addrs & RTA_NETMASK)) { 1903*a59fa508Sjl138328 rcip->ri_addrs |= RTA_NETMASK; 1904*a59fa508Sjl138328 sin = &rcip->ri_mask.sin; 19057c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(mask); 19067c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 19077c478bd9Sstevel@tonic-gate } 19087c478bd9Sstevel@tonic-gate } 19097c478bd9Sstevel@tonic-gate 19107c478bd9Sstevel@tonic-gate static in_addr_t 19117c478bd9Sstevel@tonic-gate inet_makesubnetmask(in_addr_t addr, in_addr_t mask) 19127c478bd9Sstevel@tonic-gate { 19137c478bd9Sstevel@tonic-gate int n; 19147c478bd9Sstevel@tonic-gate struct ifconf ifc; 19157c478bd9Sstevel@tonic-gate struct ifreq ifreq; 19167c478bd9Sstevel@tonic-gate struct ifreq *ifr; 19177c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 19187c478bd9Sstevel@tonic-gate char *buf; 19197c478bd9Sstevel@tonic-gate int numifs; 19207c478bd9Sstevel@tonic-gate size_t bufsize; 19217c478bd9Sstevel@tonic-gate int iosoc; 19227c478bd9Sstevel@tonic-gate in_addr_t if_addr, if_mask; 19237c478bd9Sstevel@tonic-gate in_addr_t if_subnetmask = 0; 19247c478bd9Sstevel@tonic-gate short if_flags; 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate if (mask == 0) 19277c478bd9Sstevel@tonic-gate return (0); 19287c478bd9Sstevel@tonic-gate if ((iosoc = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 19297c478bd9Sstevel@tonic-gate quit("socket", errno); 19307c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFNUM, (char *)&numifs) < 0) 19317c478bd9Sstevel@tonic-gate quit("ioctl", errno); 19327c478bd9Sstevel@tonic-gate bufsize = numifs * sizeof (struct ifreq); 19337c478bd9Sstevel@tonic-gate buf = malloc(bufsize); 19347c478bd9Sstevel@tonic-gate if (buf == NULL) 19357c478bd9Sstevel@tonic-gate quit("malloc", errno); 19367c478bd9Sstevel@tonic-gate (void) memset(&ifc, 0, sizeof (ifc)); 19377c478bd9Sstevel@tonic-gate ifc.ifc_len = bufsize; 19387c478bd9Sstevel@tonic-gate ifc.ifc_buf = buf; 19397c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFCONF, (char *)&ifc) < 0) 19407c478bd9Sstevel@tonic-gate quit("ioctl (get interface configuration)", errno); 19417c478bd9Sstevel@tonic-gate /* Let's check to see if this is maybe a local subnet route. */ 19427c478bd9Sstevel@tonic-gate ifr = ifc.ifc_req; 19437c478bd9Sstevel@tonic-gate for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { 19447c478bd9Sstevel@tonic-gate ifreq = *ifr; 19457c478bd9Sstevel@tonic-gate /* LINTED */ 19467c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr->ifr_addr; 19477c478bd9Sstevel@tonic-gate if_addr = ntohl(sin->sin_addr.s_addr); 19487c478bd9Sstevel@tonic-gate 19497c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFFLAGS, (char *)&ifreq) < 0) 19507c478bd9Sstevel@tonic-gate quit("ioctl (get interface flags)", errno); 19517c478bd9Sstevel@tonic-gate if ((ifreq.ifr_flags & IFF_UP) == 0) 19527c478bd9Sstevel@tonic-gate continue; 19537c478bd9Sstevel@tonic-gate if_flags = ifreq.ifr_flags; 19547c478bd9Sstevel@tonic-gate 19557c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFNETMASK, (char *)&ifreq) < 0) 19567c478bd9Sstevel@tonic-gate quit("ioctl (get netmask)", errno); 19577c478bd9Sstevel@tonic-gate /* LINTED */ 19587c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifreq.ifr_addr; 19597c478bd9Sstevel@tonic-gate if_mask = ntohl(sin->sin_addr.s_addr); 19607c478bd9Sstevel@tonic-gate if ((if_addr & mask) == (addr & mask)) { 19617c478bd9Sstevel@tonic-gate /* 19627c478bd9Sstevel@tonic-gate * Don't trust pt-pt interfaces if there are 19637c478bd9Sstevel@tonic-gate * other interfaces. 19647c478bd9Sstevel@tonic-gate */ 19657c478bd9Sstevel@tonic-gate if (if_flags & IFF_POINTOPOINT) { 19667c478bd9Sstevel@tonic-gate if_subnetmask = if_mask; 19677c478bd9Sstevel@tonic-gate continue; 19687c478bd9Sstevel@tonic-gate } 19697c478bd9Sstevel@tonic-gate /* 19707c478bd9Sstevel@tonic-gate * Fine. Just assume the same net mask as the 19717c478bd9Sstevel@tonic-gate * directly attached subnet interface is using. 19727c478bd9Sstevel@tonic-gate */ 19737c478bd9Sstevel@tonic-gate return (if_mask); 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate } 19767c478bd9Sstevel@tonic-gate if (if_subnetmask != 0) 19777c478bd9Sstevel@tonic-gate return (if_subnetmask); 19787c478bd9Sstevel@tonic-gate return (mask); 19797c478bd9Sstevel@tonic-gate } 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate /* 1982*a59fa508Sjl138328 * Interpret an argument as a network address of some kind. 19837c478bd9Sstevel@tonic-gate * 19847c478bd9Sstevel@tonic-gate * If the address family is one looked up in getaddr() using one of the 19857c478bd9Sstevel@tonic-gate * getipnodebyX() functions (currently only AF_INET6), then callers should 19867c478bd9Sstevel@tonic-gate * freehostent() the returned "struct hostent" pointer if one was passed in. 1987*a59fa508Sjl138328 * 1988*a59fa508Sjl138328 * If exit_on_error is true, this function will cause route to exit on error by 1989*a59fa508Sjl138328 * calling syntax_error(). Otherwise, it returns B_TRUE on success or B_FALSE 1990*a59fa508Sjl138328 * on failure. 19917c478bd9Sstevel@tonic-gate */ 19927c478bd9Sstevel@tonic-gate static boolean_t 1993*a59fa508Sjl138328 getaddr(rtcmd_irep_t *rcip, int which, char *s, addr_type_t atype) 19947c478bd9Sstevel@tonic-gate { 1995*a59fa508Sjl138328 su_t *su; 1996*a59fa508Sjl138328 struct hostent **hpp; 19977c478bd9Sstevel@tonic-gate struct hostent *hp; 1998*a59fa508Sjl138328 int masklen; 19997c478bd9Sstevel@tonic-gate 2000*a59fa508Sjl138328 if (which == RTA_GATEWAY) { 2001*a59fa508Sjl138328 hpp = &(rcip->ri_gate_hp); 2002*a59fa508Sjl138328 } else { 20037a23074eSdduvall hpp = &hp; 2004*a59fa508Sjl138328 } 20057c478bd9Sstevel@tonic-gate *hpp = NULL; 2006*a59fa508Sjl138328 2007*a59fa508Sjl138328 rcip->ri_addrs |= which; 20087c478bd9Sstevel@tonic-gate switch (which) { 20097c478bd9Sstevel@tonic-gate case RTA_DST: 2010*a59fa508Sjl138328 save_string(&rcip->ri_dest_str, s); 2011*a59fa508Sjl138328 su = &rcip->ri_dst; 2012*a59fa508Sjl138328 su->sa.sa_family = rcip->ri_af; 20137c478bd9Sstevel@tonic-gate break; 20147c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 2015*a59fa508Sjl138328 save_string(&rcip->ri_gate_str, s); 2016*a59fa508Sjl138328 su = &rcip->ri_gate; 2017*a59fa508Sjl138328 su->sa.sa_family = rcip->ri_af; 20187c478bd9Sstevel@tonic-gate break; 20197c478bd9Sstevel@tonic-gate case RTA_NETMASK: 2020*a59fa508Sjl138328 su = &rcip->ri_mask; 2021*a59fa508Sjl138328 su->sa.sa_family = rcip->ri_af; 20227c478bd9Sstevel@tonic-gate break; 20237c478bd9Sstevel@tonic-gate case RTA_IFP: 2024*a59fa508Sjl138328 save_string(&rcip->ri_ifp_str, s); 2025*a59fa508Sjl138328 return (B_TRUE); 20267c478bd9Sstevel@tonic-gate /* 20277c478bd9Sstevel@tonic-gate * RTA_SRC has overloaded meaning. It can represent the 20287c478bd9Sstevel@tonic-gate * src address of incoming or outgoing packets. 20297c478bd9Sstevel@tonic-gate */ 20307c478bd9Sstevel@tonic-gate case RTA_IFA: 2031*a59fa508Sjl138328 su = &rcip->ri_ifa; 2032*a59fa508Sjl138328 su->sa.sa_family = rcip->ri_af; 20337c478bd9Sstevel@tonic-gate break; 20347c478bd9Sstevel@tonic-gate case RTA_SRC: 2035*a59fa508Sjl138328 su = &rcip->ri_src; 2036*a59fa508Sjl138328 su->sa.sa_family = rcip->ri_af; 20377c478bd9Sstevel@tonic-gate break; 20387c478bd9Sstevel@tonic-gate default: 20397c478bd9Sstevel@tonic-gate /* NOTREACHED */ 20407c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 20417c478bd9Sstevel@tonic-gate /* NOTREACHED */ 20427c478bd9Sstevel@tonic-gate } 20437c478bd9Sstevel@tonic-gate if (strcmp(s, "default") == 0) { 20447c478bd9Sstevel@tonic-gate if (which == RTA_DST) { 2045*a59fa508Sjl138328 return (getaddr(rcip, RTA_NETMASK, s, ADDR_TYPE_NET)); 20467c478bd9Sstevel@tonic-gate } 20477c478bd9Sstevel@tonic-gate if (which == RTA_SRC) { 20487c478bd9Sstevel@tonic-gate return (B_TRUE); 20497c478bd9Sstevel@tonic-gate } 2050*a59fa508Sjl138328 return (B_TRUE); 20517c478bd9Sstevel@tonic-gate } 2052*a59fa508Sjl138328 switch (rcip->ri_af) { 20537c478bd9Sstevel@tonic-gate case AF_LINK: 20547c478bd9Sstevel@tonic-gate link_addr(s, &su->sdl); 20557c478bd9Sstevel@tonic-gate return (B_TRUE); 20567c478bd9Sstevel@tonic-gate case PF_ROUTE: 20577c478bd9Sstevel@tonic-gate sockaddr(s, &su->sa); 20587c478bd9Sstevel@tonic-gate return (B_TRUE); 20597c478bd9Sstevel@tonic-gate case AF_INET6: 20607c478bd9Sstevel@tonic-gate switch (which) { 20617c478bd9Sstevel@tonic-gate case RTA_DST: 2062*a59fa508Sjl138328 if (!in6_getaddr(s, &su->sin6, &masklen, hpp)) { 2063*a59fa508Sjl138328 return (B_FALSE); 20647c478bd9Sstevel@tonic-gate } 2065*a59fa508Sjl138328 if (masklen != NO_PREFIX) { 2066*a59fa508Sjl138328 (void) memset(&rcip->ri_mask.sin6.sin6_addr, 0, 2067*a59fa508Sjl138328 sizeof (rcip->ri_mask.sin6.sin6_addr)); 20687a23074eSdduvall if (!in_prefixlentomask(masklen, IPV6_ABITS, 2069*a59fa508Sjl138328 (uchar_t *)&rcip->ri_mask.sin6.sin6_addr)) { 2070*a59fa508Sjl138328 syntax_error(gettext( 2071*a59fa508Sjl138328 "route: bad prefix length: %d\n"), 2072*a59fa508Sjl138328 masklen); 2073*a59fa508Sjl138328 return (B_FALSE); 20747c478bd9Sstevel@tonic-gate } 2075*a59fa508Sjl138328 rcip->ri_mask.sin6.sin6_family = rcip->ri_af; 2076*a59fa508Sjl138328 rcip->ri_addrs |= RTA_NETMASK; 20777c478bd9Sstevel@tonic-gate } 2078*a59fa508Sjl138328 return (B_TRUE); 20797c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 20807c478bd9Sstevel@tonic-gate case RTA_IFA: 20817c478bd9Sstevel@tonic-gate case RTA_SRC: 2082*a59fa508Sjl138328 return (in6_getaddr(s, &su->sin6, NULL, hpp)); 20837c478bd9Sstevel@tonic-gate case RTA_NETMASK: 2084*a59fa508Sjl138328 syntax_error( 20857c478bd9Sstevel@tonic-gate gettext("route: -netmask not supported for IPv6: " 2086*a59fa508Sjl138328 "use <prefix>/<prefix-length> instead\n")); 2087*a59fa508Sjl138328 return (B_FALSE); 20887c478bd9Sstevel@tonic-gate default: 20897c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 20907c478bd9Sstevel@tonic-gate /* NOTREACHED */ 20917c478bd9Sstevel@tonic-gate } 20927c478bd9Sstevel@tonic-gate case AF_INET: 20937c478bd9Sstevel@tonic-gate switch (which) { 20947c478bd9Sstevel@tonic-gate case RTA_DST: 2095*a59fa508Sjl138328 if (!in_getaddr(s, &su->sin, &masklen, which, hpp, 2096*a59fa508Sjl138328 atype, rcip)) { 2097*a59fa508Sjl138328 return (B_FALSE); 20987c478bd9Sstevel@tonic-gate } 2099*a59fa508Sjl138328 if (masklen != NO_PREFIX) { 2100*a59fa508Sjl138328 (void) memset(&rcip->ri_mask.sin.sin_addr, 0, 2101*a59fa508Sjl138328 sizeof (rcip->ri_mask.sin.sin_addr)); 21027a23074eSdduvall if (!in_prefixlentomask(masklen, IP_ABITS, 2103*a59fa508Sjl138328 (uchar_t *)&rcip->ri_mask.sin.sin_addr)) { 2104*a59fa508Sjl138328 syntax_error(gettext( 2105*a59fa508Sjl138328 "route: bad prefix length: %d\n"), 2106*a59fa508Sjl138328 masklen); 2107*a59fa508Sjl138328 return (B_FALSE); 21087c478bd9Sstevel@tonic-gate } 2109*a59fa508Sjl138328 rcip->ri_mask.sin.sin_family = rcip->ri_af; 2110*a59fa508Sjl138328 rcip->ri_addrs |= RTA_NETMASK; 21117c478bd9Sstevel@tonic-gate } 2112*a59fa508Sjl138328 return (B_TRUE); 21137c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 21147c478bd9Sstevel@tonic-gate case RTA_IFA: 21157c478bd9Sstevel@tonic-gate case RTA_NETMASK: 21167c478bd9Sstevel@tonic-gate case RTA_SRC: 2117*a59fa508Sjl138328 return (in_getaddr(s, &su->sin, NULL, which, hpp, atype, 2118*a59fa508Sjl138328 rcip)); 21197c478bd9Sstevel@tonic-gate default: 21207c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 21217c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21227c478bd9Sstevel@tonic-gate } 21237c478bd9Sstevel@tonic-gate default: 21247c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 21257c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21267c478bd9Sstevel@tonic-gate } 2127*a59fa508Sjl138328 return (B_TRUE); 21287c478bd9Sstevel@tonic-gate } 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate /* 21317c478bd9Sstevel@tonic-gate * Interpret an argument as an IPv4 network address of some kind, 2132*a59fa508Sjl138328 * returning B_TRUE on success or B_FALSE on failure. 2133*a59fa508Sjl138328 * This function will cause an exit() on failure if exit_on_failure is set. 2134*a59fa508Sjl138328 * 2135*a59fa508Sjl138328 * Note that this tries host interpretation before network interpretation, 2136*a59fa508Sjl138328 * except when -net has been given and the destination address is being parsed. 21377c478bd9Sstevel@tonic-gate * 21387c478bd9Sstevel@tonic-gate * If the plenp argument is non-NULL, allow <addr>/<n> syntax and 21397c478bd9Sstevel@tonic-gate * pass out <n> in *plenp. 21407c478bd9Sstevel@tonic-gate * If <n> doesn't parse return BAD_ADDR as *plenp. 21417c478bd9Sstevel@tonic-gate * If no /<n> is present return NO_PREFIX as *plenp. 21427c478bd9Sstevel@tonic-gate */ 21437c478bd9Sstevel@tonic-gate static boolean_t 21447c478bd9Sstevel@tonic-gate in_getaddr(char *s, struct sockaddr_in *sin, int *plenp, int which, 2145*a59fa508Sjl138328 struct hostent **hpp, addr_type_t atype, rtcmd_irep_t *rcip) 21467c478bd9Sstevel@tonic-gate { 21477c478bd9Sstevel@tonic-gate struct hostent *hp; 21487c478bd9Sstevel@tonic-gate struct netent *np; 21497c478bd9Sstevel@tonic-gate in_addr_t val; 21507c478bd9Sstevel@tonic-gate char str[BUFSIZ]; 21517c478bd9Sstevel@tonic-gate 2152*a59fa508Sjl138328 (void) strlcpy(str, s, sizeof (str)); 21537c478bd9Sstevel@tonic-gate 21547c478bd9Sstevel@tonic-gate /* 2155*a59fa508Sjl138328 * If plenp is non-NULL, /<n> syntax for netmask is allowed. 21567c478bd9Sstevel@tonic-gate */ 21577c478bd9Sstevel@tonic-gate if (plenp != NULL) { 21587c478bd9Sstevel@tonic-gate char *cp; 21597c478bd9Sstevel@tonic-gate 21607c478bd9Sstevel@tonic-gate *plenp = in_getprefixlen(str, IP_ABITS); 21617c478bd9Sstevel@tonic-gate if (*plenp == BAD_ADDR) 21627c478bd9Sstevel@tonic-gate return (B_FALSE); 21637c478bd9Sstevel@tonic-gate cp = strchr(str, '/'); 21647c478bd9Sstevel@tonic-gate if (cp != NULL) 21657c478bd9Sstevel@tonic-gate *cp = '\0'; 21667c478bd9Sstevel@tonic-gate } else if (strchr(str, '/') != NULL) { 2167*a59fa508Sjl138328 syntax_error(gettext("route: %s: unexpected '/'\n"), str); 2168*a59fa508Sjl138328 return (B_FALSE); 21697c478bd9Sstevel@tonic-gate } 21707c478bd9Sstevel@tonic-gate 21717c478bd9Sstevel@tonic-gate (void) memset(sin, 0, sizeof (*sin)); 21727c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 21737c478bd9Sstevel@tonic-gate 21747c478bd9Sstevel@tonic-gate /* 2175*a59fa508Sjl138328 * Handle 255.255.255.255 as a special case first. 21767c478bd9Sstevel@tonic-gate */ 2177*a59fa508Sjl138328 if (strcmp(str, "255.255.255.255") == 0) { 2178*a59fa508Sjl138328 sin->sin_addr.s_addr = INADDR_BROADCAST; 21797c478bd9Sstevel@tonic-gate return (B_TRUE); 21807c478bd9Sstevel@tonic-gate } 2181*a59fa508Sjl138328 2182*a59fa508Sjl138328 val = inet_addr(str); 2183*a59fa508Sjl138328 if (val != (in_addr_t)-1) { 2184*a59fa508Sjl138328 /* Numeric address */ 2185*a59fa508Sjl138328 sin->sin_addr.s_addr = val; 2186*a59fa508Sjl138328 if (which == RTA_DST) { 2187*a59fa508Sjl138328 if (atype == ADDR_TYPE_NET || 2188*a59fa508Sjl138328 (atype == ADDR_TYPE_ANY && 2189*a59fa508Sjl138328 inet_lnaof(sin->sin_addr) == INADDR_ANY)) { 2190*a59fa508Sjl138328 /* This looks like a network address. */ 2191*a59fa508Sjl138328 inet_makenetandmask(rcip, ntohl(val), 2192*a59fa508Sjl138328 sin); 21937c478bd9Sstevel@tonic-gate } 2194*a59fa508Sjl138328 } 2195*a59fa508Sjl138328 return (B_TRUE); 2196*a59fa508Sjl138328 } 2197*a59fa508Sjl138328 /* Host or net name */ 2198*a59fa508Sjl138328 if (which != RTA_DST || atype != ADDR_TYPE_NET) { 2199*a59fa508Sjl138328 /* A host name is allowed. */ 2200*a59fa508Sjl138328 if ((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); 22047c478bd9Sstevel@tonic-gate return (B_TRUE); 22057c478bd9Sstevel@tonic-gate } 22067c478bd9Sstevel@tonic-gate } 2207*a59fa508Sjl138328 if (atype != ADDR_TYPE_HOST) { 2208*a59fa508Sjl138328 /* A network name is allowed */ 2209*a59fa508Sjl138328 if ((np = getnetbyname(str)) != NULL && 2210*a59fa508Sjl138328 (val = np->n_net) != 0) { 2211*a59fa508Sjl138328 if (which == RTA_DST) { 2212*a59fa508Sjl138328 inet_makenetandmask(rcip, val, sin); 2213*a59fa508Sjl138328 } 2214*a59fa508Sjl138328 return (B_TRUE); 2215*a59fa508Sjl138328 } 2216*a59fa508Sjl138328 } 2217*a59fa508Sjl138328 syntax_error(gettext("%s: bad value\n"), s); 2218*a59fa508Sjl138328 return (B_FALSE); 22197a23074eSdduvall } 22207c478bd9Sstevel@tonic-gate 22217c478bd9Sstevel@tonic-gate /* 22227c478bd9Sstevel@tonic-gate * Interpret an argument as an IPv6 network address of some kind, 2223*a59fa508Sjl138328 * returning B_TRUE on success or B_FALSE on failure. 2224*a59fa508Sjl138328 * This function will cause an exit() on failure if exit_on_failure is set. 22257c478bd9Sstevel@tonic-gate * 22267c478bd9Sstevel@tonic-gate * If the last argument is non-NULL allow a <addr>/<n> syntax and 22277c478bd9Sstevel@tonic-gate * pass out <n> in *plenp. 22287c478bd9Sstevel@tonic-gate * If <n> doesn't parse return BAD_ADDR as *plenp. 22297c478bd9Sstevel@tonic-gate * If no /<n> is present return NO_PREFIX as *plenp. 22307c478bd9Sstevel@tonic-gate */ 22317c478bd9Sstevel@tonic-gate static boolean_t 22327c478bd9Sstevel@tonic-gate in6_getaddr(char *s, struct sockaddr_in6 *sin6, int *plenp, 22337c478bd9Sstevel@tonic-gate struct hostent **hpp) 22347c478bd9Sstevel@tonic-gate { 22357c478bd9Sstevel@tonic-gate struct hostent *hp; 22367c478bd9Sstevel@tonic-gate char str[BUFSIZ]; 22377c478bd9Sstevel@tonic-gate int error_num; 22387c478bd9Sstevel@tonic-gate 2239*a59fa508Sjl138328 (void) strlcpy(str, s, sizeof (str)); 22407c478bd9Sstevel@tonic-gate 22417c478bd9Sstevel@tonic-gate /* 2242*a59fa508Sjl138328 * If plenp is non-NULL, /<n> syntax for netmask is allowed. 22437c478bd9Sstevel@tonic-gate */ 22447c478bd9Sstevel@tonic-gate if (plenp != NULL) { 22457c478bd9Sstevel@tonic-gate char *cp; 22467c478bd9Sstevel@tonic-gate 22477c478bd9Sstevel@tonic-gate *plenp = in_getprefixlen(str, IPV6_ABITS); 22487c478bd9Sstevel@tonic-gate if (*plenp == BAD_ADDR) 22497c478bd9Sstevel@tonic-gate return (B_FALSE); 22507c478bd9Sstevel@tonic-gate cp = strchr(str, '/'); 22517c478bd9Sstevel@tonic-gate if (cp != NULL) 22527c478bd9Sstevel@tonic-gate *cp = '\0'; 22537c478bd9Sstevel@tonic-gate } else if (strchr(str, '/') != NULL) { 2254*a59fa508Sjl138328 syntax_error(gettext("route: %s: unexpected '/'\n"), str); 2255*a59fa508Sjl138328 return (B_FALSE); 22567c478bd9Sstevel@tonic-gate } 22577c478bd9Sstevel@tonic-gate 22587c478bd9Sstevel@tonic-gate (void) memset(sin6, 0, sizeof (struct sockaddr_in6)); 22597c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 22607c478bd9Sstevel@tonic-gate 22617c478bd9Sstevel@tonic-gate hp = getipnodebyname(str, AF_INET6, 0, &error_num); 22627c478bd9Sstevel@tonic-gate if (hp != NULL) { 22637c478bd9Sstevel@tonic-gate *hpp = hp; 22647c478bd9Sstevel@tonic-gate (void) memmove(&sin6->sin6_addr, hp->h_addr, hp->h_length); 22657c478bd9Sstevel@tonic-gate return (B_TRUE); 22667c478bd9Sstevel@tonic-gate } 22677c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 2268*a59fa508Sjl138328 /* 2269*a59fa508Sjl138328 * This isn't a problem if we aren't going to use the address 2270*a59fa508Sjl138328 * right away. 2271*a59fa508Sjl138328 */ 2272*a59fa508Sjl138328 if (!exit_on_error) { 2273*a59fa508Sjl138328 return (B_TRUE); 22743f33f4f7Sjl138328 } 2275*a59fa508Sjl138328 syntax_error(gettext("route: %s: bad address (try " 2276*a59fa508Sjl138328 "again later)\n"), s); 2277*a59fa508Sjl138328 return (B_FALSE); 2278*a59fa508Sjl138328 } 2279*a59fa508Sjl138328 syntax_error(gettext("route: %s: bad address\n"), s); 2280*a59fa508Sjl138328 return (B_FALSE); 22817c478bd9Sstevel@tonic-gate } 22827c478bd9Sstevel@tonic-gate 22837c478bd9Sstevel@tonic-gate /* 2284*a59fa508Sjl138328 * Parse <addr>/<n> syntax and return the integer n. 2285*a59fa508Sjl138328 * If <addr> is missing or <n> is not a valid integer, this function calls 2286*a59fa508Sjl138328 * syntax_error() and returns BAD_ADDR. 2287*a59fa508Sjl138328 * if n is not between 0 and max_plen inclusive, this functions calls 2288*a59fa508Sjl138328 * syntax_error() and returns BAD_ADDR. 2289*a59fa508Sjl138328 * If /<n> is not present, this function returns NO_PREFIX. 2290*a59fa508Sjl138328 * The string addr is not modified. 22917c478bd9Sstevel@tonic-gate */ 22927c478bd9Sstevel@tonic-gate int 22937c478bd9Sstevel@tonic-gate in_getprefixlen(char *addr, int max_plen) 22947c478bd9Sstevel@tonic-gate { 22957c478bd9Sstevel@tonic-gate int prefixlen; 22967c478bd9Sstevel@tonic-gate char *str, *end; 22977c478bd9Sstevel@tonic-gate 22987c478bd9Sstevel@tonic-gate str = strchr(addr, '/'); 2299*a59fa508Sjl138328 if (str == addr) { 2300*a59fa508Sjl138328 syntax_error(gettext("route: %s: unexpected '/'\n"), addr); 2301*a59fa508Sjl138328 return (BAD_ADDR); 2302*a59fa508Sjl138328 } 23037c478bd9Sstevel@tonic-gate if (str == NULL) 23047c478bd9Sstevel@tonic-gate return (NO_PREFIX); 23057c478bd9Sstevel@tonic-gate str++; 23067c478bd9Sstevel@tonic-gate 2307*a59fa508Sjl138328 errno = 0; 2308*a59fa508Sjl138328 prefixlen = strtoul(str, &end, 10); 2309*a59fa508Sjl138328 if (errno != 0 || str == end) { 2310*a59fa508Sjl138328 syntax_error(gettext("route: bad prefix length %s\n"), str); 23117c478bd9Sstevel@tonic-gate return (BAD_ADDR); 2312*a59fa508Sjl138328 } 2313*a59fa508Sjl138328 if (prefixlen > max_plen) { 2314*a59fa508Sjl138328 syntax_error(gettext("route: prefix length %s out of range\n"), 2315*a59fa508Sjl138328 str); 23167c478bd9Sstevel@tonic-gate return (BAD_ADDR); 2317*a59fa508Sjl138328 } 23187c478bd9Sstevel@tonic-gate return (prefixlen); 23197c478bd9Sstevel@tonic-gate } 23207c478bd9Sstevel@tonic-gate 23217c478bd9Sstevel@tonic-gate /* 23227c478bd9Sstevel@tonic-gate * Convert a prefix length to a mask. 23237c478bd9Sstevel@tonic-gate * Returns B_TRUE if ok. B_FALSE otherwise. 23247c478bd9Sstevel@tonic-gate * Assumes the mask array is zeroed by the caller. 23257c478bd9Sstevel@tonic-gate */ 23267c478bd9Sstevel@tonic-gate boolean_t 23277c478bd9Sstevel@tonic-gate in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 23287c478bd9Sstevel@tonic-gate { 23297c478bd9Sstevel@tonic-gate if (prefixlen < 0 || prefixlen > maxlen) 23307c478bd9Sstevel@tonic-gate return (B_FALSE); 23317c478bd9Sstevel@tonic-gate 23327c478bd9Sstevel@tonic-gate while (prefixlen > 0) { 23337c478bd9Sstevel@tonic-gate if (prefixlen >= 8) { 23347c478bd9Sstevel@tonic-gate *mask++ = 0xFF; 23357c478bd9Sstevel@tonic-gate prefixlen -= 8; 23367c478bd9Sstevel@tonic-gate continue; 23377c478bd9Sstevel@tonic-gate } 23387c478bd9Sstevel@tonic-gate *mask |= 1 << (8 - prefixlen); 23397c478bd9Sstevel@tonic-gate prefixlen--; 23407c478bd9Sstevel@tonic-gate } 23417c478bd9Sstevel@tonic-gate return (B_TRUE); 23427c478bd9Sstevel@tonic-gate } 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate void 23457c478bd9Sstevel@tonic-gate rtmonitor(int argc, char *argv[]) 23467c478bd9Sstevel@tonic-gate { 23477c478bd9Sstevel@tonic-gate int n; 23487c478bd9Sstevel@tonic-gate intmax_t msg[2048 / sizeof (intmax_t)]; 23497c478bd9Sstevel@tonic-gate 23507c478bd9Sstevel@tonic-gate if (tflag) 23517c478bd9Sstevel@tonic-gate exit(0); 23527c478bd9Sstevel@tonic-gate verbose = B_TRUE; 23537c478bd9Sstevel@tonic-gate if (argc > 1) { 23547c478bd9Sstevel@tonic-gate argv++; 23557c478bd9Sstevel@tonic-gate if (argc == 2 && **argv == '-') { 23567c478bd9Sstevel@tonic-gate switch (keyword(*argv + 1)) { 23577c478bd9Sstevel@tonic-gate case K_INET: 23587c478bd9Sstevel@tonic-gate af = AF_INET; 23597c478bd9Sstevel@tonic-gate break; 23607c478bd9Sstevel@tonic-gate case K_LINK: 23617c478bd9Sstevel@tonic-gate af = AF_LINK; 23627c478bd9Sstevel@tonic-gate break; 23637c478bd9Sstevel@tonic-gate case K_INET6: 23647c478bd9Sstevel@tonic-gate af = AF_INET6; 23657c478bd9Sstevel@tonic-gate break; 23667c478bd9Sstevel@tonic-gate default: 23677c478bd9Sstevel@tonic-gate usage(*argv); 23687c478bd9Sstevel@tonic-gate /* NOTREACHED */ 23697c478bd9Sstevel@tonic-gate } 23707c478bd9Sstevel@tonic-gate } else { 23717c478bd9Sstevel@tonic-gate usage(*argv); 23727c478bd9Sstevel@tonic-gate } 23737c478bd9Sstevel@tonic-gate (void) close(s); 23747c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, af); 23757c478bd9Sstevel@tonic-gate if (s < 0) 23767c478bd9Sstevel@tonic-gate quit("socket", errno); 23777c478bd9Sstevel@tonic-gate } 23787c478bd9Sstevel@tonic-gate for (;;) { 23797c478bd9Sstevel@tonic-gate n = read(s, msg, sizeof (msg)); 23807c478bd9Sstevel@tonic-gate if (n <= 0) 23817c478bd9Sstevel@tonic-gate quit("read", errno); 23827c478bd9Sstevel@tonic-gate (void) printf("got message of size %d\n", n); 23837c478bd9Sstevel@tonic-gate print_rtmsg((struct rt_msghdr *)msg, n); 23847c478bd9Sstevel@tonic-gate } 23857c478bd9Sstevel@tonic-gate } 23867c478bd9Sstevel@tonic-gate 23877c478bd9Sstevel@tonic-gate int 2388*a59fa508Sjl138328 rtmsg(rtcmd_irep_t *newrt) 23897c478bd9Sstevel@tonic-gate { 23907c478bd9Sstevel@tonic-gate static int seq; 23917c478bd9Sstevel@tonic-gate int rlen; 23927c478bd9Sstevel@tonic-gate char *cp = m_rtmsg.m_space; 23937c478bd9Sstevel@tonic-gate int l; 23947c478bd9Sstevel@tonic-gate 23957c478bd9Sstevel@tonic-gate errno = 0; 23967c478bd9Sstevel@tonic-gate (void) memset(&m_rtmsg, 0, sizeof (m_rtmsg)); 2397*a59fa508Sjl138328 2398*a59fa508Sjl138328 if (newrt->ri_cmd == RTM_GET) { 2399*a59fa508Sjl138328 newrt->ri_ifp.sa.sa_family = AF_LINK; 2400*a59fa508Sjl138328 newrt->ri_addrs |= RTA_IFP; 24017c478bd9Sstevel@tonic-gate } 2402*a59fa508Sjl138328 24037c478bd9Sstevel@tonic-gate #define rtm m_rtmsg.m_rtm 2404*a59fa508Sjl138328 rtm.rtm_type = newrt->ri_cmd; 2405*a59fa508Sjl138328 rtm.rtm_flags = newrt->ri_flags; 24067c478bd9Sstevel@tonic-gate rtm.rtm_version = RTM_VERSION; 24077c478bd9Sstevel@tonic-gate rtm.rtm_seq = ++seq; 2408*a59fa508Sjl138328 rtm.rtm_addrs = newrt->ri_addrs; 2409*a59fa508Sjl138328 rtm.rtm_rmx = newrt->ri_metrics; 2410*a59fa508Sjl138328 rtm.rtm_inits = newrt->ri_inits; 24117c478bd9Sstevel@tonic-gate 24127c478bd9Sstevel@tonic-gate #define NEXTADDR(w, u) \ 2413*a59fa508Sjl138328 if (newrt->ri_addrs & (w)) { \ 24147c478bd9Sstevel@tonic-gate l = ROUNDUP_LONG(salen(&u.sa)); \ 24157c478bd9Sstevel@tonic-gate (void) memmove(cp, &(u), l); \ 24167c478bd9Sstevel@tonic-gate cp += l; \ 24177c478bd9Sstevel@tonic-gate if (verbose) \ 24187c478bd9Sstevel@tonic-gate sodump(&(u), #u); \ 24197c478bd9Sstevel@tonic-gate } 2420*a59fa508Sjl138328 NEXTADDR(RTA_DST, newrt->ri_dst); 2421*a59fa508Sjl138328 NEXTADDR(RTA_GATEWAY, newrt->ri_gate); 2422*a59fa508Sjl138328 NEXTADDR(RTA_NETMASK, newrt->ri_mask); 2423*a59fa508Sjl138328 NEXTADDR(RTA_IFP, newrt->ri_ifp); 2424*a59fa508Sjl138328 NEXTADDR(RTA_IFA, newrt->ri_ifa); 24257c478bd9Sstevel@tonic-gate /* 24267c478bd9Sstevel@tonic-gate * RTA_SRC has overloaded meaning. It can represent the 24277c478bd9Sstevel@tonic-gate * src address of incoming or outgoing packets. 24287c478bd9Sstevel@tonic-gate */ 2429*a59fa508Sjl138328 NEXTADDR(RTA_SRC, newrt->ri_src); 24307c478bd9Sstevel@tonic-gate #undef NEXTADDR 24317c478bd9Sstevel@tonic-gate rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 24327c478bd9Sstevel@tonic-gate if (verbose) 24337c478bd9Sstevel@tonic-gate print_rtmsg(&rtm, l); 24347c478bd9Sstevel@tonic-gate if (debugonly) 24357c478bd9Sstevel@tonic-gate return (0); 24367c478bd9Sstevel@tonic-gate if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 24377c478bd9Sstevel@tonic-gate switch (errno) { 24387c478bd9Sstevel@tonic-gate case ESRCH: 24397c478bd9Sstevel@tonic-gate case EBUSY: 24407c478bd9Sstevel@tonic-gate case ENOBUFS: 24417c478bd9Sstevel@tonic-gate case EEXIST: 24427c478bd9Sstevel@tonic-gate case ENETUNREACH: 24437c478bd9Sstevel@tonic-gate case EHOSTUNREACH: 24447c478bd9Sstevel@tonic-gate case EPERM: 24457c478bd9Sstevel@tonic-gate break; 24467c478bd9Sstevel@tonic-gate default: 24477c478bd9Sstevel@tonic-gate perror(gettext("writing to routing socket")); 24487c478bd9Sstevel@tonic-gate break; 24497c478bd9Sstevel@tonic-gate } 24507c478bd9Sstevel@tonic-gate return (-1); 24517c478bd9Sstevel@tonic-gate } else if (rlen < (int)rtm.rtm_msglen) { 24527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 24537c478bd9Sstevel@tonic-gate gettext("route: write to routing socket got only %d for " 24547c478bd9Sstevel@tonic-gate "len\n"), rlen); 24557c478bd9Sstevel@tonic-gate return (-1); 24567c478bd9Sstevel@tonic-gate } 2457*a59fa508Sjl138328 if (newrt->ri_cmd == RTM_GET) { 24587c478bd9Sstevel@tonic-gate do { 24597c478bd9Sstevel@tonic-gate l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg)); 24607c478bd9Sstevel@tonic-gate } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 24617c478bd9Sstevel@tonic-gate if (l < 0) { 24627c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 24637c478bd9Sstevel@tonic-gate gettext("route: read from routing socket: %s\n"), 24647c478bd9Sstevel@tonic-gate strerror(errno)); 24657c478bd9Sstevel@tonic-gate } else { 2466*a59fa508Sjl138328 print_getmsg(newrt, &rtm, l); 24677c478bd9Sstevel@tonic-gate } 24687c478bd9Sstevel@tonic-gate } 24697c478bd9Sstevel@tonic-gate #undef rtm 24707c478bd9Sstevel@tonic-gate return (0); 24717c478bd9Sstevel@tonic-gate } 24727c478bd9Sstevel@tonic-gate 24737c478bd9Sstevel@tonic-gate static char *msgtypes[] = { 24747c478bd9Sstevel@tonic-gate "", 24757c478bd9Sstevel@tonic-gate "RTM_ADD: Add Route", 24767c478bd9Sstevel@tonic-gate "RTM_DELETE: Delete Route", 24777c478bd9Sstevel@tonic-gate "RTM_CHANGE: Change Metrics or flags", 24787c478bd9Sstevel@tonic-gate "RTM_GET: Report Metrics", 24797c478bd9Sstevel@tonic-gate "RTM_LOSING: Kernel Suspects Partitioning", 24807c478bd9Sstevel@tonic-gate "RTM_REDIRECT: Told to use different route", 24817c478bd9Sstevel@tonic-gate "RTM_MISS: Lookup failed on this address", 24827c478bd9Sstevel@tonic-gate "RTM_LOCK: fix specified metrics", 24837c478bd9Sstevel@tonic-gate "RTM_OLDADD: caused by SIOCADDRT", 24847c478bd9Sstevel@tonic-gate "RTM_OLDDEL: caused by SIOCDELRT", 24857c478bd9Sstevel@tonic-gate "RTM_RESOLVE: Route created by cloning", 24867c478bd9Sstevel@tonic-gate "RTM_NEWADDR: address being added to iface", 24877c478bd9Sstevel@tonic-gate "RTM_DELADDR: address being removed from iface", 24887c478bd9Sstevel@tonic-gate "RTM_IFINFO: iface status change", 24897c478bd9Sstevel@tonic-gate 0, 24907c478bd9Sstevel@tonic-gate }; 24917c478bd9Sstevel@tonic-gate 24927c478bd9Sstevel@tonic-gate #define NMSGTYPES (sizeof (msgtypes) / sizeof (msgtypes[0])) 24937c478bd9Sstevel@tonic-gate 24947c478bd9Sstevel@tonic-gate static char metricnames[] = 24957c478bd9Sstevel@tonic-gate "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount" 24967c478bd9Sstevel@tonic-gate "\1mtu"; 24977c478bd9Sstevel@tonic-gate static char routeflags[] = 24987c478bd9Sstevel@tonic-gate "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT" 24997c478bd9Sstevel@tonic-gate "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 25007c478bd9Sstevel@tonic-gate "\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC"; 25017c478bd9Sstevel@tonic-gate static char ifnetflags[] = 25027c478bd9Sstevel@tonic-gate "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP" 25037c478bd9Sstevel@tonic-gate "\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST" 25047c478bd9Sstevel@tonic-gate "\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE" 25057c478bd9Sstevel@tonic-gate "\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF" 25067c478bd9Sstevel@tonic-gate "\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6" 25077c478bd9Sstevel@tonic-gate "\033MIP\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE" 25087c478bd9Sstevel@tonic-gate "\041XRESOLV\042COS\043PREFERRED\044TEMPORARY"; 25097c478bd9Sstevel@tonic-gate static char addrnames[] = 25107c478bd9Sstevel@tonic-gate "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC"; 25117c478bd9Sstevel@tonic-gate 25127c478bd9Sstevel@tonic-gate void 25137c478bd9Sstevel@tonic-gate print_rtmsg(struct rt_msghdr *rtm, int msglen) 25147c478bd9Sstevel@tonic-gate { 25157c478bd9Sstevel@tonic-gate struct if_msghdr *ifm; 25167c478bd9Sstevel@tonic-gate struct ifa_msghdr *ifam; 25177c478bd9Sstevel@tonic-gate 25187c478bd9Sstevel@tonic-gate if (!verbose) 25197c478bd9Sstevel@tonic-gate return; 25207c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 25217c478bd9Sstevel@tonic-gate (void) printf("routing message version %d not understood\n", 25227c478bd9Sstevel@tonic-gate rtm->rtm_version); 25237c478bd9Sstevel@tonic-gate return; 25247c478bd9Sstevel@tonic-gate } 25257c478bd9Sstevel@tonic-gate if (rtm->rtm_msglen > (ushort_t)msglen) { 25267c478bd9Sstevel@tonic-gate (void) printf("message length mismatch, in packet %d, " 25277c478bd9Sstevel@tonic-gate "returned %d\n", 25287c478bd9Sstevel@tonic-gate rtm->rtm_msglen, msglen); 25297c478bd9Sstevel@tonic-gate } 25307c478bd9Sstevel@tonic-gate /* 25317c478bd9Sstevel@tonic-gate * Since rtm->rtm_type is unsigned, we'll just check the case of zero 25327c478bd9Sstevel@tonic-gate * and the upper-bound of (NMSGTYPES - 1). 25337c478bd9Sstevel@tonic-gate */ 25347c478bd9Sstevel@tonic-gate if (rtm->rtm_type == 0 || rtm->rtm_type >= (NMSGTYPES - 1)) { 25357c478bd9Sstevel@tonic-gate (void) printf("routing message type %d not understood\n", 25367c478bd9Sstevel@tonic-gate rtm->rtm_type); 25377c478bd9Sstevel@tonic-gate return; 25387c478bd9Sstevel@tonic-gate } 25397c478bd9Sstevel@tonic-gate (void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen); 25407c478bd9Sstevel@tonic-gate switch (rtm->rtm_type) { 25417c478bd9Sstevel@tonic-gate case RTM_IFINFO: 25427c478bd9Sstevel@tonic-gate ifm = (struct if_msghdr *)rtm; 25437c478bd9Sstevel@tonic-gate (void) printf("if# %d, flags:", ifm->ifm_index); 25447c478bd9Sstevel@tonic-gate bprintf(stdout, ifm->ifm_flags, ifnetflags); 25457c478bd9Sstevel@tonic-gate pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 25467c478bd9Sstevel@tonic-gate break; 25477c478bd9Sstevel@tonic-gate case RTM_NEWADDR: 25487c478bd9Sstevel@tonic-gate case RTM_DELADDR: 25497c478bd9Sstevel@tonic-gate ifam = (struct ifa_msghdr *)rtm; 25507c478bd9Sstevel@tonic-gate (void) printf("metric %d, flags:", ifam->ifam_metric); 25517c478bd9Sstevel@tonic-gate bprintf(stdout, ifam->ifam_flags, routeflags); 25527c478bd9Sstevel@tonic-gate pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); 25537c478bd9Sstevel@tonic-gate break; 25547c478bd9Sstevel@tonic-gate default: 25557c478bd9Sstevel@tonic-gate (void) printf("pid: %ld, seq %d, errno %d, flags:", 25567c478bd9Sstevel@tonic-gate rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 25577c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_flags, routeflags); 25587c478bd9Sstevel@tonic-gate pmsg_common(rtm); 25597c478bd9Sstevel@tonic-gate } 25607c478bd9Sstevel@tonic-gate } 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate void 2563*a59fa508Sjl138328 print_getmsg(rtcmd_irep_t *req_rt, struct rt_msghdr *rtm, int msglen) 25647c478bd9Sstevel@tonic-gate { 25657c478bd9Sstevel@tonic-gate struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL; 25667c478bd9Sstevel@tonic-gate struct sockaddr_dl *ifp = NULL; 25677c478bd9Sstevel@tonic-gate struct sockaddr *sa; 25687c478bd9Sstevel@tonic-gate char *cp; 25697c478bd9Sstevel@tonic-gate int i; 25707c478bd9Sstevel@tonic-gate 2571*a59fa508Sjl138328 (void) printf(" route to: %s\n", routename(&req_rt->ri_dst.sa)); 25727c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 25737c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 25747c478bd9Sstevel@tonic-gate gettext("routing message version %d not understood\n"), 25757c478bd9Sstevel@tonic-gate rtm->rtm_version); 25767c478bd9Sstevel@tonic-gate return; 25777c478bd9Sstevel@tonic-gate } 25787c478bd9Sstevel@tonic-gate if (rtm->rtm_msglen > (ushort_t)msglen) { 25797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 25807c478bd9Sstevel@tonic-gate gettext("message length mismatch, in packet %d, " 25817c478bd9Sstevel@tonic-gate "returned %d\n"), rtm->rtm_msglen, msglen); 25827c478bd9Sstevel@tonic-gate } 25837c478bd9Sstevel@tonic-gate if (rtm->rtm_errno) { 25847c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "RTM_GET: %s (errno %d)\n", 25857c478bd9Sstevel@tonic-gate strerror(rtm->rtm_errno), rtm->rtm_errno); 25867c478bd9Sstevel@tonic-gate return; 25877c478bd9Sstevel@tonic-gate } 25887c478bd9Sstevel@tonic-gate cp = ((char *)(rtm + 1)); 25897c478bd9Sstevel@tonic-gate if (rtm->rtm_addrs != 0) { 25907c478bd9Sstevel@tonic-gate for (i = 1; i != 0; i <<= 1) { 25917c478bd9Sstevel@tonic-gate if (i & rtm->rtm_addrs) { 25927c478bd9Sstevel@tonic-gate /* LINTED */ 25937c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)cp; 25947c478bd9Sstevel@tonic-gate switch (i) { 25957c478bd9Sstevel@tonic-gate case RTA_DST: 25967c478bd9Sstevel@tonic-gate dst = sa; 25977c478bd9Sstevel@tonic-gate break; 25987c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 25997c478bd9Sstevel@tonic-gate gate = sa; 26007c478bd9Sstevel@tonic-gate break; 26017c478bd9Sstevel@tonic-gate case RTA_NETMASK: 26027c478bd9Sstevel@tonic-gate mask = sa; 26037c478bd9Sstevel@tonic-gate break; 26047c478bd9Sstevel@tonic-gate case RTA_IFP: 26057c478bd9Sstevel@tonic-gate if (sa->sa_family == AF_LINK && 26067c478bd9Sstevel@tonic-gate ((struct sockaddr_dl *)sa)-> 26077c478bd9Sstevel@tonic-gate sdl_nlen != 0) 26087c478bd9Sstevel@tonic-gate ifp = (struct sockaddr_dl *)sa; 26097c478bd9Sstevel@tonic-gate break; 26107c478bd9Sstevel@tonic-gate case RTA_SRC: 26117c478bd9Sstevel@tonic-gate src = sa; 26127c478bd9Sstevel@tonic-gate break; 26137c478bd9Sstevel@tonic-gate } 26147c478bd9Sstevel@tonic-gate ADVANCE(cp, sa); 26157c478bd9Sstevel@tonic-gate } 26167c478bd9Sstevel@tonic-gate } 26177c478bd9Sstevel@tonic-gate } 26187c478bd9Sstevel@tonic-gate if (dst != NULL && mask != NULL) 26197c478bd9Sstevel@tonic-gate mask->sa_family = dst->sa_family; /* XXX */ 26207c478bd9Sstevel@tonic-gate if (dst != NULL) 26217c478bd9Sstevel@tonic-gate (void) printf("destination: %s\n", routename(dst)); 26227c478bd9Sstevel@tonic-gate if (mask != NULL) { 26237c478bd9Sstevel@tonic-gate boolean_t savenflag = nflag; 26247c478bd9Sstevel@tonic-gate 26257c478bd9Sstevel@tonic-gate nflag = B_TRUE; 26267c478bd9Sstevel@tonic-gate (void) printf(" mask: %s\n", routename(mask)); 26277c478bd9Sstevel@tonic-gate nflag = savenflag; 26287c478bd9Sstevel@tonic-gate } 26297c478bd9Sstevel@tonic-gate if (gate != NULL && rtm->rtm_flags & RTF_GATEWAY) 26307c478bd9Sstevel@tonic-gate (void) printf(" gateway: %s\n", routename(gate)); 26317c478bd9Sstevel@tonic-gate if (src != NULL && rtm->rtm_flags & RTF_SETSRC) 26327c478bd9Sstevel@tonic-gate (void) printf(" setsrc: %s\n", routename(src)); 26337c478bd9Sstevel@tonic-gate if (ifp != NULL) { 26347c478bd9Sstevel@tonic-gate if (verbose) { 26357c478bd9Sstevel@tonic-gate int i; 26367c478bd9Sstevel@tonic-gate 26377c478bd9Sstevel@tonic-gate (void) printf(" interface: %.*s index %d address ", 26387c478bd9Sstevel@tonic-gate ifp->sdl_nlen, ifp->sdl_data, ifp->sdl_index); 26397c478bd9Sstevel@tonic-gate for (i = ifp->sdl_nlen; 26407c478bd9Sstevel@tonic-gate i < ifp->sdl_nlen + ifp->sdl_alen; 26417c478bd9Sstevel@tonic-gate i++) { 26427c478bd9Sstevel@tonic-gate (void) printf("%02x ", 26437c478bd9Sstevel@tonic-gate ifp->sdl_data[i] & 0xFF); 26447c478bd9Sstevel@tonic-gate } 26457c478bd9Sstevel@tonic-gate (void) printf("\n"); 26467c478bd9Sstevel@tonic-gate } else { 26477c478bd9Sstevel@tonic-gate (void) printf(" interface: %.*s\n", 26487c478bd9Sstevel@tonic-gate ifp->sdl_nlen, ifp->sdl_data); 26497c478bd9Sstevel@tonic-gate } 26507c478bd9Sstevel@tonic-gate } 26517c478bd9Sstevel@tonic-gate (void) printf(" flags: "); 26527c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_flags, routeflags); 26537c478bd9Sstevel@tonic-gate 26547c478bd9Sstevel@tonic-gate #define lock(f) ((rtm->rtm_rmx.rmx_locks & RTV_ ## f) ? 'L' : ' ') 26557c478bd9Sstevel@tonic-gate #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 26567c478bd9Sstevel@tonic-gate 26577c478bd9Sstevel@tonic-gate (void) printf("\n%s\n", " recvpipe sendpipe ssthresh rtt,ms " 26587c478bd9Sstevel@tonic-gate "rttvar,ms hopcount mtu expire"); 26597c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 26607c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 26617c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 26627c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 26637c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 26647c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 26657c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 26667c478bd9Sstevel@tonic-gate if (rtm->rtm_rmx.rmx_expire) 26677c478bd9Sstevel@tonic-gate rtm->rtm_rmx.rmx_expire -= time(0); 26687c478bd9Sstevel@tonic-gate (void) printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 26697c478bd9Sstevel@tonic-gate #undef lock 26707c478bd9Sstevel@tonic-gate #undef msec 26717c478bd9Sstevel@tonic-gate #define RTA_IGN \ 26727c478bd9Sstevel@tonic-gate (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC) 26737c478bd9Sstevel@tonic-gate if (verbose) { 26747c478bd9Sstevel@tonic-gate pmsg_common(rtm); 26757c478bd9Sstevel@tonic-gate } else if (rtm->rtm_addrs &~ RTA_IGN) { 26767c478bd9Sstevel@tonic-gate (void) printf("sockaddrs: "); 26777c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_addrs, addrnames); 26787c478bd9Sstevel@tonic-gate (void) putchar('\n'); 26797c478bd9Sstevel@tonic-gate } 26807c478bd9Sstevel@tonic-gate #undef RTA_IGN 26817c478bd9Sstevel@tonic-gate } 26827c478bd9Sstevel@tonic-gate 26837c478bd9Sstevel@tonic-gate void 26847c478bd9Sstevel@tonic-gate pmsg_common(struct rt_msghdr *rtm) 26857c478bd9Sstevel@tonic-gate { 26867c478bd9Sstevel@tonic-gate (void) printf("\nlocks: "); 26877c478bd9Sstevel@tonic-gate bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames); 26887c478bd9Sstevel@tonic-gate (void) printf(" inits: "); 26897c478bd9Sstevel@tonic-gate bprintf(stdout, (int)rtm->rtm_inits, metricnames); 26907c478bd9Sstevel@tonic-gate pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs); 26917c478bd9Sstevel@tonic-gate } 26927c478bd9Sstevel@tonic-gate 26937c478bd9Sstevel@tonic-gate void 26947c478bd9Sstevel@tonic-gate pmsg_addrs(char *cp, int addrs) 26957c478bd9Sstevel@tonic-gate { 26967c478bd9Sstevel@tonic-gate struct sockaddr *sa; 26977c478bd9Sstevel@tonic-gate int i; 26987c478bd9Sstevel@tonic-gate 26997c478bd9Sstevel@tonic-gate if (addrs == 0) 27007c478bd9Sstevel@tonic-gate return; 27017c478bd9Sstevel@tonic-gate (void) printf("\nsockaddrs: "); 27027c478bd9Sstevel@tonic-gate bprintf(stdout, addrs, addrnames); 27037c478bd9Sstevel@tonic-gate (void) putchar('\n'); 27047c478bd9Sstevel@tonic-gate for (i = 1; i != 0; i <<= 1) { 27057c478bd9Sstevel@tonic-gate if (i & addrs) { 27067c478bd9Sstevel@tonic-gate /* LINTED */ 27077c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)cp; 27087c478bd9Sstevel@tonic-gate (void) printf(" %s", routename(sa)); 27097c478bd9Sstevel@tonic-gate ADVANCE(cp, sa); 27107c478bd9Sstevel@tonic-gate } 27117c478bd9Sstevel@tonic-gate } 27127c478bd9Sstevel@tonic-gate (void) putchar('\n'); 27137c478bd9Sstevel@tonic-gate (void) fflush(stdout); 27147c478bd9Sstevel@tonic-gate } 27157c478bd9Sstevel@tonic-gate 27167c478bd9Sstevel@tonic-gate void 27177c478bd9Sstevel@tonic-gate bprintf(FILE *fp, int b, char *s) 27187c478bd9Sstevel@tonic-gate { 27197c478bd9Sstevel@tonic-gate int i; 27207c478bd9Sstevel@tonic-gate boolean_t gotsome = B_FALSE; 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate if (b == 0) 27237c478bd9Sstevel@tonic-gate return; 27247c478bd9Sstevel@tonic-gate while ((i = *s++) != 0) { 27257c478bd9Sstevel@tonic-gate if (b & (1 << (i - 1))) { 27267c478bd9Sstevel@tonic-gate if (!gotsome) 27277c478bd9Sstevel@tonic-gate i = '<'; 27287c478bd9Sstevel@tonic-gate else 27297c478bd9Sstevel@tonic-gate i = ','; 27307c478bd9Sstevel@tonic-gate (void) putc(i, fp); 27317c478bd9Sstevel@tonic-gate gotsome = B_TRUE; 27327c478bd9Sstevel@tonic-gate for (; (i = *s) > ' '; s++) 27337c478bd9Sstevel@tonic-gate (void) putc(i, fp); 27347c478bd9Sstevel@tonic-gate } else { 27357c478bd9Sstevel@tonic-gate while (*s > ' ') 27367c478bd9Sstevel@tonic-gate s++; 27377c478bd9Sstevel@tonic-gate } 27387c478bd9Sstevel@tonic-gate } 27397c478bd9Sstevel@tonic-gate if (gotsome) 27407c478bd9Sstevel@tonic-gate (void) putc('>', fp); 27417c478bd9Sstevel@tonic-gate } 27427c478bd9Sstevel@tonic-gate 27437c478bd9Sstevel@tonic-gate int 2744*a59fa508Sjl138328 keyword(const char *cp) 27457c478bd9Sstevel@tonic-gate { 27467c478bd9Sstevel@tonic-gate struct keytab *kt = keywords; 27477c478bd9Sstevel@tonic-gate 27487c478bd9Sstevel@tonic-gate while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 27497c478bd9Sstevel@tonic-gate kt++; 27507c478bd9Sstevel@tonic-gate return (kt->kt_i); 27517c478bd9Sstevel@tonic-gate } 27527c478bd9Sstevel@tonic-gate 27537c478bd9Sstevel@tonic-gate void 2754*a59fa508Sjl138328 sodump(su_t *su, char *which) 27557c478bd9Sstevel@tonic-gate { 27567c478bd9Sstevel@tonic-gate static char obuf[INET6_ADDRSTRLEN]; 27577c478bd9Sstevel@tonic-gate 27587c478bd9Sstevel@tonic-gate switch (su->sa.sa_family) { 27597c478bd9Sstevel@tonic-gate case AF_LINK: 27607c478bd9Sstevel@tonic-gate (void) printf("%s: link %s; ", 27617c478bd9Sstevel@tonic-gate which, link_ntoa(&su->sdl)); 27627c478bd9Sstevel@tonic-gate break; 27637c478bd9Sstevel@tonic-gate case AF_INET: 27647c478bd9Sstevel@tonic-gate (void) printf("%s: inet %s; ", 27657c478bd9Sstevel@tonic-gate which, inet_ntoa(su->sin.sin_addr)); 27667c478bd9Sstevel@tonic-gate break; 27677c478bd9Sstevel@tonic-gate case AF_INET6: 27687c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, (void *)&su->sin6.sin6_addr, obuf, 27697c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN) != NULL) { 27707c478bd9Sstevel@tonic-gate (void) printf("%s: inet6 %s; ", which, obuf); 27717c478bd9Sstevel@tonic-gate break; 27727c478bd9Sstevel@tonic-gate } 27737c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 27747c478bd9Sstevel@tonic-gate default: 27757c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 27767c478bd9Sstevel@tonic-gate /* NOTREACHED */ 27777c478bd9Sstevel@tonic-gate } 27787c478bd9Sstevel@tonic-gate (void) fflush(stdout); 27797c478bd9Sstevel@tonic-gate } 27807c478bd9Sstevel@tonic-gate 27817c478bd9Sstevel@tonic-gate /* States */ 27827c478bd9Sstevel@tonic-gate #define VIRGIN 0 27837c478bd9Sstevel@tonic-gate #define GOTONE 1 27847c478bd9Sstevel@tonic-gate #define GOTTWO 2 27857c478bd9Sstevel@tonic-gate #define RESET 3 27867c478bd9Sstevel@tonic-gate /* Inputs */ 27877c478bd9Sstevel@tonic-gate #define DIGIT (4*0) 27887c478bd9Sstevel@tonic-gate #define END (4*1) 27897c478bd9Sstevel@tonic-gate #define DELIM (4*2) 27907c478bd9Sstevel@tonic-gate #define LETTER (4*3) 27917c478bd9Sstevel@tonic-gate 27927c478bd9Sstevel@tonic-gate void 27937c478bd9Sstevel@tonic-gate sockaddr(char *addr, struct sockaddr *sa) 27947c478bd9Sstevel@tonic-gate { 27957c478bd9Sstevel@tonic-gate char *cp = (char *)sa; 27967c478bd9Sstevel@tonic-gate int size = salen(sa); 27977c478bd9Sstevel@tonic-gate char *cplim = cp + size; 27987c478bd9Sstevel@tonic-gate int byte = 0, state = VIRGIN, new; 27997c478bd9Sstevel@tonic-gate 28007c478bd9Sstevel@tonic-gate (void) memset(cp, 0, size); 28017c478bd9Sstevel@tonic-gate cp++; 28027c478bd9Sstevel@tonic-gate do { 28037c478bd9Sstevel@tonic-gate if ((*addr >= '0') && (*addr <= '9')) { 28047c478bd9Sstevel@tonic-gate new = *addr - '0'; 28057c478bd9Sstevel@tonic-gate } else if ((*addr >= 'a') && (*addr <= 'f')) { 28067c478bd9Sstevel@tonic-gate new = *addr - 'a' + 10; 28077c478bd9Sstevel@tonic-gate } else if ((*addr >= 'A') && (*addr <= 'F')) { 28087c478bd9Sstevel@tonic-gate new = *addr - 'A' + 10; 28097c478bd9Sstevel@tonic-gate } else if (*addr == 0) { 28107c478bd9Sstevel@tonic-gate state |= END; 28117c478bd9Sstevel@tonic-gate } else { 28127c478bd9Sstevel@tonic-gate state |= DELIM; 28137c478bd9Sstevel@tonic-gate } 28147c478bd9Sstevel@tonic-gate addr++; 28157c478bd9Sstevel@tonic-gate switch (state /* | INPUT */) { 28167c478bd9Sstevel@tonic-gate case GOTTWO | DIGIT: 28177c478bd9Sstevel@tonic-gate *cp++ = byte; 28187c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 28197c478bd9Sstevel@tonic-gate case VIRGIN | DIGIT: 28207c478bd9Sstevel@tonic-gate state = GOTONE; byte = new; continue; 28217c478bd9Sstevel@tonic-gate case GOTONE | DIGIT: 28227c478bd9Sstevel@tonic-gate state = GOTTWO; byte = new + (byte << 4); continue; 28237c478bd9Sstevel@tonic-gate default: /* | DELIM */ 28247c478bd9Sstevel@tonic-gate state = VIRGIN; *cp++ = byte; byte = 0; continue; 28257c478bd9Sstevel@tonic-gate case GOTONE | END: 28267c478bd9Sstevel@tonic-gate case GOTTWO | END: 28277c478bd9Sstevel@tonic-gate *cp++ = byte; 28287c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 28297c478bd9Sstevel@tonic-gate case VIRGIN | END: 28307c478bd9Sstevel@tonic-gate break; 28317c478bd9Sstevel@tonic-gate } 28327c478bd9Sstevel@tonic-gate break; 28337c478bd9Sstevel@tonic-gate } while (cp < cplim); 28347c478bd9Sstevel@tonic-gate } 28357c478bd9Sstevel@tonic-gate 28367c478bd9Sstevel@tonic-gate int 28377c478bd9Sstevel@tonic-gate salen(struct sockaddr *sa) 28387c478bd9Sstevel@tonic-gate { 28397c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 28407c478bd9Sstevel@tonic-gate case AF_INET: 28417c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_in)); 28427c478bd9Sstevel@tonic-gate case AF_LINK: 28437c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_dl)); 28447c478bd9Sstevel@tonic-gate case AF_INET6: 28457c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_in6)); 28467c478bd9Sstevel@tonic-gate default: 28477c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr)); 28487c478bd9Sstevel@tonic-gate } 28497c478bd9Sstevel@tonic-gate } 28507c478bd9Sstevel@tonic-gate 28517c478bd9Sstevel@tonic-gate void 28527c478bd9Sstevel@tonic-gate link_addr(const char *addr, struct sockaddr_dl *sdl) 28537c478bd9Sstevel@tonic-gate { 28547c478bd9Sstevel@tonic-gate char *cp = sdl->sdl_data; 28557c478bd9Sstevel@tonic-gate char *cplim = sizeof (struct sockaddr_dl) + (char *)sdl; 28567c478bd9Sstevel@tonic-gate int byte = 0, state = VIRGIN, new; 28577c478bd9Sstevel@tonic-gate 28587c478bd9Sstevel@tonic-gate (void) memset(sdl, 0, sizeof (struct sockaddr_dl)); 28597c478bd9Sstevel@tonic-gate sdl->sdl_family = AF_LINK; 28607c478bd9Sstevel@tonic-gate do { 28617c478bd9Sstevel@tonic-gate state &= ~LETTER; 28627c478bd9Sstevel@tonic-gate if ((*addr >= '0') && (*addr <= '9')) { 28637c478bd9Sstevel@tonic-gate new = *addr - '0'; 28647c478bd9Sstevel@tonic-gate } else if ((*addr >= 'a') && (*addr <= 'f')) { 28657c478bd9Sstevel@tonic-gate new = *addr - 'a' + 10; 28667c478bd9Sstevel@tonic-gate } else if ((*addr >= 'A') && (*addr <= 'F')) { 28677c478bd9Sstevel@tonic-gate new = *addr - 'A' + 10; 28687c478bd9Sstevel@tonic-gate } else if (*addr == 0) { 28697c478bd9Sstevel@tonic-gate state |= END; 28707c478bd9Sstevel@tonic-gate } else if (state == VIRGIN && 28717c478bd9Sstevel@tonic-gate (((*addr >= 'A') && (*addr <= 'Z')) || 28727c478bd9Sstevel@tonic-gate ((*addr >= 'a') && (*addr <= 'z')))) { 28737c478bd9Sstevel@tonic-gate state |= LETTER; 28747c478bd9Sstevel@tonic-gate } else { 28757c478bd9Sstevel@tonic-gate state |= DELIM; 28767c478bd9Sstevel@tonic-gate } 28777c478bd9Sstevel@tonic-gate addr++; 28787c478bd9Sstevel@tonic-gate switch (state /* | INPUT */) { 28797c478bd9Sstevel@tonic-gate case VIRGIN | DIGIT: 28807c478bd9Sstevel@tonic-gate case VIRGIN | LETTER: 28817c478bd9Sstevel@tonic-gate *cp++ = addr[-1]; 28827c478bd9Sstevel@tonic-gate continue; 28837c478bd9Sstevel@tonic-gate case VIRGIN | DELIM: 28847c478bd9Sstevel@tonic-gate state = RESET; 28857c478bd9Sstevel@tonic-gate sdl->sdl_nlen = cp - sdl->sdl_data; 28867c478bd9Sstevel@tonic-gate continue; 28877c478bd9Sstevel@tonic-gate case GOTTWO | DIGIT: 28887c478bd9Sstevel@tonic-gate *cp++ = byte; 28897c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 28907c478bd9Sstevel@tonic-gate case RESET | DIGIT: 28917c478bd9Sstevel@tonic-gate state = GOTONE; 28927c478bd9Sstevel@tonic-gate byte = new; 28937c478bd9Sstevel@tonic-gate continue; 28947c478bd9Sstevel@tonic-gate case GOTONE | DIGIT: 28957c478bd9Sstevel@tonic-gate state = GOTTWO; 28967c478bd9Sstevel@tonic-gate byte = new + (byte << 4); 28977c478bd9Sstevel@tonic-gate continue; 28987c478bd9Sstevel@tonic-gate default: /* | DELIM */ 28997c478bd9Sstevel@tonic-gate state = RESET; 29007c478bd9Sstevel@tonic-gate *cp++ = byte; 29017c478bd9Sstevel@tonic-gate byte = 0; 29027c478bd9Sstevel@tonic-gate continue; 29037c478bd9Sstevel@tonic-gate case GOTONE | END: 29047c478bd9Sstevel@tonic-gate case GOTTWO | END: 29057c478bd9Sstevel@tonic-gate *cp++ = byte; 29067c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 29077c478bd9Sstevel@tonic-gate case RESET | END: 29087c478bd9Sstevel@tonic-gate break; 29097c478bd9Sstevel@tonic-gate } 29107c478bd9Sstevel@tonic-gate break; 29117c478bd9Sstevel@tonic-gate } while (cp < cplim); 29127c478bd9Sstevel@tonic-gate sdl->sdl_alen = cp - LLADDR(sdl); 29137c478bd9Sstevel@tonic-gate } 29147c478bd9Sstevel@tonic-gate 29157c478bd9Sstevel@tonic-gate static char hexlist[] = "0123456789abcdef"; 29167c478bd9Sstevel@tonic-gate 29177c478bd9Sstevel@tonic-gate char * 29187c478bd9Sstevel@tonic-gate link_ntoa(const struct sockaddr_dl *sdl) 29197c478bd9Sstevel@tonic-gate { 29207c478bd9Sstevel@tonic-gate static char obuf[64]; 29217c478bd9Sstevel@tonic-gate char *out = obuf; 29227c478bd9Sstevel@tonic-gate int i; 29237c478bd9Sstevel@tonic-gate uchar_t *in = (uchar_t *)LLADDR(sdl); 29247c478bd9Sstevel@tonic-gate uchar_t *inlim = in + sdl->sdl_alen; 29257c478bd9Sstevel@tonic-gate boolean_t firsttime = B_TRUE; 29267c478bd9Sstevel@tonic-gate 29277c478bd9Sstevel@tonic-gate if (sdl->sdl_nlen) { 29287c478bd9Sstevel@tonic-gate (void) memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen); 29297c478bd9Sstevel@tonic-gate out += sdl->sdl_nlen; 29307c478bd9Sstevel@tonic-gate if (sdl->sdl_alen) 29317c478bd9Sstevel@tonic-gate *out++ = ':'; 29327c478bd9Sstevel@tonic-gate } 29337c478bd9Sstevel@tonic-gate while (in < inlim) { 29347c478bd9Sstevel@tonic-gate if (firsttime) 29357c478bd9Sstevel@tonic-gate firsttime = B_FALSE; 29367c478bd9Sstevel@tonic-gate else 29377c478bd9Sstevel@tonic-gate *out++ = '.'; 29387c478bd9Sstevel@tonic-gate i = *in++; 29397c478bd9Sstevel@tonic-gate if (i > 0xf) { 29407c478bd9Sstevel@tonic-gate out[1] = hexlist[i & 0xf]; 29417c478bd9Sstevel@tonic-gate i >>= 4; 29427c478bd9Sstevel@tonic-gate out[0] = hexlist[i]; 29437c478bd9Sstevel@tonic-gate out += 2; 29447c478bd9Sstevel@tonic-gate } else { 29457c478bd9Sstevel@tonic-gate *out++ = hexlist[i]; 29467c478bd9Sstevel@tonic-gate } 29477c478bd9Sstevel@tonic-gate } 29487c478bd9Sstevel@tonic-gate *out = 0; 29497c478bd9Sstevel@tonic-gate return (obuf); 29507c478bd9Sstevel@tonic-gate } 29517c478bd9Sstevel@tonic-gate 29527c478bd9Sstevel@tonic-gate static mib_item_t * 29537c478bd9Sstevel@tonic-gate mibget(int sd) 29547c478bd9Sstevel@tonic-gate { 29557c478bd9Sstevel@tonic-gate intmax_t buf[512 / sizeof (intmax_t)]; 29567c478bd9Sstevel@tonic-gate int flags; 29577c478bd9Sstevel@tonic-gate int i, j, getcode; 29587c478bd9Sstevel@tonic-gate struct strbuf ctlbuf, databuf; 29597c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; 29607c478bd9Sstevel@tonic-gate struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; 29617c478bd9Sstevel@tonic-gate struct T_error_ack *tea = (struct T_error_ack *)buf; 29627c478bd9Sstevel@tonic-gate struct opthdr *req; 29637c478bd9Sstevel@tonic-gate mib_item_t *first_item = NULL; 29647c478bd9Sstevel@tonic-gate mib_item_t *last_item = NULL; 29657c478bd9Sstevel@tonic-gate mib_item_t *temp; 29667c478bd9Sstevel@tonic-gate 29677c478bd9Sstevel@tonic-gate tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 29687c478bd9Sstevel@tonic-gate tor->OPT_offset = sizeof (struct T_optmgmt_req); 29697c478bd9Sstevel@tonic-gate tor->OPT_length = sizeof (struct opthdr); 29707c478bd9Sstevel@tonic-gate tor->MGMT_flags = T_CURRENT; 29717c478bd9Sstevel@tonic-gate req = (struct opthdr *)&tor[1]; 29727c478bd9Sstevel@tonic-gate req->level = MIB2_IP; /* any MIB2_xxx value ok here */ 29737c478bd9Sstevel@tonic-gate req->name = 0; 29747c478bd9Sstevel@tonic-gate req->len = 0; 29757c478bd9Sstevel@tonic-gate 29767c478bd9Sstevel@tonic-gate ctlbuf.buf = (char *)buf; 29777c478bd9Sstevel@tonic-gate ctlbuf.len = tor->OPT_length + tor->OPT_offset; 29787c478bd9Sstevel@tonic-gate flags = 0; 29797c478bd9Sstevel@tonic-gate if (putmsg(sd, &ctlbuf, NULL, flags) < 0) { 29807c478bd9Sstevel@tonic-gate perror("mibget: putmsg (ctl)"); 29817c478bd9Sstevel@tonic-gate return (NULL); 29827c478bd9Sstevel@tonic-gate } 29837c478bd9Sstevel@tonic-gate /* 29847c478bd9Sstevel@tonic-gate * each reply consists of a ctl part for one fixed structure 29857c478bd9Sstevel@tonic-gate * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK, 29867c478bd9Sstevel@tonic-gate * containing an opthdr structure. level/name identify the entry, 29877c478bd9Sstevel@tonic-gate * len is the size of the data part of the message. 29887c478bd9Sstevel@tonic-gate */ 29897c478bd9Sstevel@tonic-gate req = (struct opthdr *)&toa[1]; 29907c478bd9Sstevel@tonic-gate ctlbuf.maxlen = sizeof (buf); 29917c478bd9Sstevel@tonic-gate for (j = 1; ; j++) { 29927c478bd9Sstevel@tonic-gate flags = 0; 29937c478bd9Sstevel@tonic-gate getcode = getmsg(sd, &ctlbuf, NULL, &flags); 29947c478bd9Sstevel@tonic-gate if (getcode < 0) { 29957c478bd9Sstevel@tonic-gate perror("mibget: getmsg (ctl)"); 29967c478bd9Sstevel@tonic-gate if (verbose) { 29977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 29987c478bd9Sstevel@tonic-gate "# level name len\n"); 29997c478bd9Sstevel@tonic-gate i = 0; 30007c478bd9Sstevel@tonic-gate for (last_item = first_item; last_item != NULL; 30017c478bd9Sstevel@tonic-gate last_item = last_item->next_item) { 30027c478bd9Sstevel@tonic-gate (void) printf("%d %4ld %5ld %ld\n", 30037c478bd9Sstevel@tonic-gate ++i, last_item->group, 30047c478bd9Sstevel@tonic-gate last_item->mib_id, 30057c478bd9Sstevel@tonic-gate last_item->length); 30067c478bd9Sstevel@tonic-gate } 30077c478bd9Sstevel@tonic-gate } 30087c478bd9Sstevel@tonic-gate break; 30097c478bd9Sstevel@tonic-gate } 30107c478bd9Sstevel@tonic-gate if (getcode == 0 && 30117c478bd9Sstevel@tonic-gate ctlbuf.len >= sizeof (struct T_optmgmt_ack) && 30127c478bd9Sstevel@tonic-gate toa->PRIM_type == T_OPTMGMT_ACK && 30137c478bd9Sstevel@tonic-gate toa->MGMT_flags == T_SUCCESS && 30147c478bd9Sstevel@tonic-gate req->len == 0) { 30157c478bd9Sstevel@tonic-gate if (verbose) { 30167c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg() %d returned EOD " 30177c478bd9Sstevel@tonic-gate "(level %lu, name %lu)\n", j, req->level, 30187c478bd9Sstevel@tonic-gate req->name); 30197c478bd9Sstevel@tonic-gate } 30207c478bd9Sstevel@tonic-gate return (first_item); /* this is EOD msg */ 30217c478bd9Sstevel@tonic-gate } 30227c478bd9Sstevel@tonic-gate 30237c478bd9Sstevel@tonic-gate if (ctlbuf.len >= sizeof (struct T_error_ack) && 30247c478bd9Sstevel@tonic-gate tea->PRIM_type == T_ERROR_ACK) { 30257c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("mibget %d gives " 30267c478bd9Sstevel@tonic-gate "T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = " 30277c478bd9Sstevel@tonic-gate "0x%lx\n"), j, tea->TLI_error, tea->UNIX_error); 30287c478bd9Sstevel@tonic-gate errno = (tea->TLI_error == TSYSERR) 30297c478bd9Sstevel@tonic-gate ? tea->UNIX_error : EPROTO; 30307c478bd9Sstevel@tonic-gate break; 30317c478bd9Sstevel@tonic-gate } 30327c478bd9Sstevel@tonic-gate 30337c478bd9Sstevel@tonic-gate if (getcode != MOREDATA || 30347c478bd9Sstevel@tonic-gate ctlbuf.len < sizeof (struct T_optmgmt_ack) || 30357c478bd9Sstevel@tonic-gate toa->PRIM_type != T_OPTMGMT_ACK || 30367c478bd9Sstevel@tonic-gate toa->MGMT_flags != T_SUCCESS) { 30377c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg(ctl) %d returned %d, " 30387c478bd9Sstevel@tonic-gate "ctlbuf.len = %d, PRIM_type = %ld\n", 30397c478bd9Sstevel@tonic-gate j, getcode, ctlbuf.len, toa->PRIM_type); 30407c478bd9Sstevel@tonic-gate if (toa->PRIM_type == T_OPTMGMT_ACK) { 30417c478bd9Sstevel@tonic-gate (void) printf("T_OPTMGMT_ACK: " 30427c478bd9Sstevel@tonic-gate "MGMT_flags = 0x%lx, req->len = %ld\n", 30437c478bd9Sstevel@tonic-gate toa->MGMT_flags, req->len); 30447c478bd9Sstevel@tonic-gate } 30457c478bd9Sstevel@tonic-gate errno = ENOMSG; 30467c478bd9Sstevel@tonic-gate break; 30477c478bd9Sstevel@tonic-gate } 30487c478bd9Sstevel@tonic-gate 30497c478bd9Sstevel@tonic-gate temp = malloc(sizeof (mib_item_t)); 30507c478bd9Sstevel@tonic-gate if (temp == NULL) { 30517c478bd9Sstevel@tonic-gate perror("mibget: malloc"); 30527c478bd9Sstevel@tonic-gate break; 30537c478bd9Sstevel@tonic-gate } 30547c478bd9Sstevel@tonic-gate if (last_item != NULL) 30557c478bd9Sstevel@tonic-gate last_item->next_item = temp; 30567c478bd9Sstevel@tonic-gate else 30577c478bd9Sstevel@tonic-gate first_item = temp; 30587c478bd9Sstevel@tonic-gate last_item = temp; 30597c478bd9Sstevel@tonic-gate last_item->next_item = NULL; 30607c478bd9Sstevel@tonic-gate last_item->group = req->level; 30617c478bd9Sstevel@tonic-gate last_item->mib_id = req->name; 30627c478bd9Sstevel@tonic-gate last_item->length = req->len; 30637c478bd9Sstevel@tonic-gate last_item->valp = malloc(req->len); 30647c478bd9Sstevel@tonic-gate if (verbose) { 30657c478bd9Sstevel@tonic-gate (void) printf("msg %d: group = %4ld mib_id = %5ld " 30667c478bd9Sstevel@tonic-gate "length = %ld\n", 30677c478bd9Sstevel@tonic-gate j, last_item->group, last_item->mib_id, 30687c478bd9Sstevel@tonic-gate last_item->length); 30697c478bd9Sstevel@tonic-gate } 30707c478bd9Sstevel@tonic-gate 30717c478bd9Sstevel@tonic-gate databuf.maxlen = last_item->length; 30727c478bd9Sstevel@tonic-gate databuf.buf = (char *)last_item->valp; 30737c478bd9Sstevel@tonic-gate databuf.len = 0; 30747c478bd9Sstevel@tonic-gate flags = 0; 30757c478bd9Sstevel@tonic-gate getcode = getmsg(sd, NULL, &databuf, &flags); 30767c478bd9Sstevel@tonic-gate if (getcode < 0) { 30777c478bd9Sstevel@tonic-gate perror("mibget: getmsg (data)"); 30787c478bd9Sstevel@tonic-gate break; 30797c478bd9Sstevel@tonic-gate } else if (getcode != 0) { 30807c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg(data) returned %d, " 30817c478bd9Sstevel@tonic-gate "databuf.maxlen = %d, databuf.len = %d\n", 30827c478bd9Sstevel@tonic-gate getcode, databuf.maxlen, databuf.len); 30837c478bd9Sstevel@tonic-gate break; 30847c478bd9Sstevel@tonic-gate } 30857c478bd9Sstevel@tonic-gate } 30867c478bd9Sstevel@tonic-gate 30877c478bd9Sstevel@tonic-gate /* 30887c478bd9Sstevel@tonic-gate * On error, free all the allocated mib_item_t objects. 30897c478bd9Sstevel@tonic-gate */ 30907c478bd9Sstevel@tonic-gate while (first_item != NULL) { 30917c478bd9Sstevel@tonic-gate last_item = first_item; 30927c478bd9Sstevel@tonic-gate first_item = first_item->next_item; 30937c478bd9Sstevel@tonic-gate free(last_item); 30947c478bd9Sstevel@tonic-gate } 30957c478bd9Sstevel@tonic-gate return (NULL); 30967c478bd9Sstevel@tonic-gate } 3097