17c478bd9Sstevel@tonic-gate /* 2*bd670b35SErik Nordmark * Copyright 2009 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 #include <sys/param.h> 497c478bd9Sstevel@tonic-gate #include <sys/file.h> 507c478bd9Sstevel@tonic-gate #include <sys/socket.h> 517c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 52a59fa508Sjl138328 #include <sys/stat.h> 537c478bd9Sstevel@tonic-gate #include <sys/stream.h> 547a23074eSdduvall #include <sys/sysmacros.h> 55a59fa508Sjl138328 #include <sys/tihdr.h> 56a59fa508Sjl138328 #include <sys/types.h> 57aee32e3dScarlsonj #include <sys/ccompile.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #include <net/if.h> 607c478bd9Sstevel@tonic-gate #include <net/route.h> 617c478bd9Sstevel@tonic-gate #include <net/if_dl.h> 627c478bd9Sstevel@tonic-gate #include <netinet/in.h> 637c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 647c478bd9Sstevel@tonic-gate #include <netdb.h> 657c478bd9Sstevel@tonic-gate #include <inet/mib2.h> 667c478bd9Sstevel@tonic-gate #include <inet/ip.h> 677c478bd9Sstevel@tonic-gate 68a59fa508Sjl138328 #include <limits.h> 697c478bd9Sstevel@tonic-gate #include <locale.h> 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate #include <errno.h> 727c478bd9Sstevel@tonic-gate #include <unistd.h> 737c478bd9Sstevel@tonic-gate #include <stdio.h> 747c478bd9Sstevel@tonic-gate #include <stdlib.h> 7545916cd2Sjpk #include <stddef.h> 767c478bd9Sstevel@tonic-gate #include <string.h> 777c478bd9Sstevel@tonic-gate #include <stropts.h> 787c478bd9Sstevel@tonic-gate #include <fcntl.h> 79a59fa508Sjl138328 #include <stdarg.h> 807c478bd9Sstevel@tonic-gate #include <assert.h> 8145916cd2Sjpk #include <strings.h> 8245916cd2Sjpk 8345916cd2Sjpk #include <libtsnet.h> 8445916cd2Sjpk #include <tsol/label.h> 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate static struct keytab { 877c478bd9Sstevel@tonic-gate char *kt_cp; 887c478bd9Sstevel@tonic-gate int kt_i; 897c478bd9Sstevel@tonic-gate } keywords[] = { 907c478bd9Sstevel@tonic-gate #define K_ADD 1 917c478bd9Sstevel@tonic-gate {"add", K_ADD}, 927c478bd9Sstevel@tonic-gate #define K_BLACKHOLE 2 937c478bd9Sstevel@tonic-gate {"blackhole", K_BLACKHOLE}, 947c478bd9Sstevel@tonic-gate #define K_CHANGE 3 957c478bd9Sstevel@tonic-gate {"change", K_CHANGE}, 967c478bd9Sstevel@tonic-gate #define K_CLONING 4 977c478bd9Sstevel@tonic-gate {"cloning", K_CLONING}, 987c478bd9Sstevel@tonic-gate #define K_DELETE 5 997c478bd9Sstevel@tonic-gate {"delete", K_DELETE}, 1007c478bd9Sstevel@tonic-gate #define K_DST 6 1017c478bd9Sstevel@tonic-gate {"dst", K_DST}, 1027c478bd9Sstevel@tonic-gate #define K_EXPIRE 7 1037c478bd9Sstevel@tonic-gate {"expire", K_EXPIRE}, 1047c478bd9Sstevel@tonic-gate #define K_FLUSH 8 1057c478bd9Sstevel@tonic-gate {"flush", K_FLUSH}, 1067c478bd9Sstevel@tonic-gate #define K_GATEWAY 9 1077c478bd9Sstevel@tonic-gate {"gateway", K_GATEWAY}, 1087c478bd9Sstevel@tonic-gate #define K_GET 11 1097c478bd9Sstevel@tonic-gate {"get", K_GET}, 1107c478bd9Sstevel@tonic-gate #define K_HOPCOUNT 12 1117c478bd9Sstevel@tonic-gate {"hopcount", K_HOPCOUNT}, 1127c478bd9Sstevel@tonic-gate #define K_HOST 13 1137c478bd9Sstevel@tonic-gate {"host", K_HOST}, 1147c478bd9Sstevel@tonic-gate #define K_IFA 14 1157c478bd9Sstevel@tonic-gate {"ifa", K_IFA}, 1167c478bd9Sstevel@tonic-gate #define K_IFACE 15 1177c478bd9Sstevel@tonic-gate {"iface", K_IFACE}, 1187c478bd9Sstevel@tonic-gate #define K_IFP 16 1197c478bd9Sstevel@tonic-gate {"ifp", K_IFP}, 1207c478bd9Sstevel@tonic-gate #define K_INET 17 1217c478bd9Sstevel@tonic-gate {"inet", K_INET}, 1227c478bd9Sstevel@tonic-gate #define K_INET6 18 1237c478bd9Sstevel@tonic-gate {"inet6", K_INET6}, 1247c478bd9Sstevel@tonic-gate #define K_INTERFACE 19 1257c478bd9Sstevel@tonic-gate {"interface", K_INTERFACE}, 1267c478bd9Sstevel@tonic-gate #define K_LINK 20 1277c478bd9Sstevel@tonic-gate {"link", K_LINK}, 1287c478bd9Sstevel@tonic-gate #define K_LOCK 21 1297c478bd9Sstevel@tonic-gate {"lock", K_LOCK}, 1307c478bd9Sstevel@tonic-gate #define K_LOCKREST 22 1317c478bd9Sstevel@tonic-gate {"lockrest", K_LOCKREST}, 1327c478bd9Sstevel@tonic-gate #define K_MASK 23 1337c478bd9Sstevel@tonic-gate {"mask", K_MASK}, 1347c478bd9Sstevel@tonic-gate #define K_MONITOR 24 1357c478bd9Sstevel@tonic-gate {"monitor", K_MONITOR}, 1367c478bd9Sstevel@tonic-gate #define K_MTU 25 1377c478bd9Sstevel@tonic-gate {"mtu", K_MTU}, 1387c478bd9Sstevel@tonic-gate #define K_NET 26 1397c478bd9Sstevel@tonic-gate {"net", K_NET}, 1407c478bd9Sstevel@tonic-gate #define K_NETMASK 27 1417c478bd9Sstevel@tonic-gate {"netmask", K_NETMASK}, 1427c478bd9Sstevel@tonic-gate #define K_NOSTATIC 28 1437c478bd9Sstevel@tonic-gate {"nostatic", K_NOSTATIC}, 1447c478bd9Sstevel@tonic-gate #define K_PRIVATE 29 1457c478bd9Sstevel@tonic-gate {"private", K_PRIVATE}, 1467c478bd9Sstevel@tonic-gate #define K_PROTO1 30 1477c478bd9Sstevel@tonic-gate {"proto1", K_PROTO1}, 1487c478bd9Sstevel@tonic-gate #define K_PROTO2 31 1497c478bd9Sstevel@tonic-gate {"proto2", K_PROTO2}, 1507c478bd9Sstevel@tonic-gate #define K_RECVPIPE 32 1517c478bd9Sstevel@tonic-gate {"recvpipe", K_RECVPIPE}, 1527c478bd9Sstevel@tonic-gate #define K_REJECT 33 1537c478bd9Sstevel@tonic-gate {"reject", K_REJECT}, 1547c478bd9Sstevel@tonic-gate #define K_RTT 34 1557c478bd9Sstevel@tonic-gate {"rtt", K_RTT}, 1567c478bd9Sstevel@tonic-gate #define K_RTTVAR 35 1577c478bd9Sstevel@tonic-gate {"rttvar", K_RTTVAR}, 1587c478bd9Sstevel@tonic-gate #define K_SA 36 1597c478bd9Sstevel@tonic-gate {"sa", K_SA}, 1607c478bd9Sstevel@tonic-gate #define K_SENDPIPE 37 1617c478bd9Sstevel@tonic-gate {"sendpipe", K_SENDPIPE}, 1627c478bd9Sstevel@tonic-gate #define K_SSTHRESH 38 1637c478bd9Sstevel@tonic-gate {"ssthresh", K_SSTHRESH}, 1647c478bd9Sstevel@tonic-gate #define K_STATIC 39 1657c478bd9Sstevel@tonic-gate {"static", K_STATIC}, 1667c478bd9Sstevel@tonic-gate #define K_XRESOLVE 40 1677c478bd9Sstevel@tonic-gate {"xresolve", K_XRESOLVE}, 1687c478bd9Sstevel@tonic-gate #define K_MULTIRT 41 1697c478bd9Sstevel@tonic-gate {"multirt", K_MULTIRT}, 1707c478bd9Sstevel@tonic-gate #define K_SETSRC 42 1717c478bd9Sstevel@tonic-gate {"setsrc", K_SETSRC}, 172a59fa508Sjl138328 #define K_SHOW 43 173a59fa508Sjl138328 {"show", K_SHOW}, 17445916cd2Sjpk #define K_SECATTR 43 17545916cd2Sjpk {"secattr", K_SECATTR}, 176*bd670b35SErik Nordmark #define K_INDIRECT 44 177*bd670b35SErik Nordmark {"indirect", K_INDIRECT}, 1787c478bd9Sstevel@tonic-gate {0, 0} 1797c478bd9Sstevel@tonic-gate }; 1807c478bd9Sstevel@tonic-gate 181a59fa508Sjl138328 /* 182a59fa508Sjl138328 * Size of buffers used to hold command lines from the saved route file as 183a59fa508Sjl138328 * well as error strings. 184a59fa508Sjl138328 */ 185a59fa508Sjl138328 #define BUF_SIZE 2048 186a59fa508Sjl138328 187a59fa508Sjl138328 typedef union sockunion { 1887c478bd9Sstevel@tonic-gate struct sockaddr sa; 1897c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 1907c478bd9Sstevel@tonic-gate struct sockaddr_dl sdl; 1917c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 192a59fa508Sjl138328 } su_t; 193a59fa508Sjl138328 194a59fa508Sjl138328 /* 195a59fa508Sjl138328 * This structure represents the digested information from parsing arguments 196a59fa508Sjl138328 * to route add, change, delete, and get. 197a59fa508Sjl138328 * 198a59fa508Sjl138328 */ 199a59fa508Sjl138328 typedef struct rtcmd_irep { 200a59fa508Sjl138328 int ri_cmd; 201a59fa508Sjl138328 int ri_flags; 202a59fa508Sjl138328 int ri_af; 203a59fa508Sjl138328 ulong_t ri_inits; 204a59fa508Sjl138328 struct rt_metrics ri_metrics; 205a59fa508Sjl138328 int ri_addrs; 206a59fa508Sjl138328 su_t ri_dst; 207a59fa508Sjl138328 char *ri_dest_str; 208a59fa508Sjl138328 su_t ri_src; 209a59fa508Sjl138328 su_t ri_gate; 210a59fa508Sjl138328 struct hostent *ri_gate_hp; 211a59fa508Sjl138328 char *ri_gate_str; 212a59fa508Sjl138328 su_t ri_mask; 213a59fa508Sjl138328 su_t ri_ifa; 214a59fa508Sjl138328 su_t ri_ifp; 215a59fa508Sjl138328 char *ri_ifp_str; 21645916cd2Sjpk int ri_rtsa_cnt; /* number of gateway security attributes */ 21745916cd2Sjpk struct rtsa_s ri_rtsa; /* enough space for one attribute */ 218a59fa508Sjl138328 } rtcmd_irep_t; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate typedef struct mib_item_s { 2217c478bd9Sstevel@tonic-gate struct mib_item_s *next_item; 2227c478bd9Sstevel@tonic-gate long group; 2237c478bd9Sstevel@tonic-gate long mib_id; 2247c478bd9Sstevel@tonic-gate long length; 2257c478bd9Sstevel@tonic-gate intmax_t *valp; 2267c478bd9Sstevel@tonic-gate } mib_item_t; 2277c478bd9Sstevel@tonic-gate 228a59fa508Sjl138328 typedef enum { 229a59fa508Sjl138328 ADDR_TYPE_ANY, 230a59fa508Sjl138328 ADDR_TYPE_HOST, 231a59fa508Sjl138328 ADDR_TYPE_NET 232a59fa508Sjl138328 } addr_type_t; 2337c478bd9Sstevel@tonic-gate 234a59fa508Sjl138328 typedef enum { 235a59fa508Sjl138328 SEARCH_MODE_NULL, 236a59fa508Sjl138328 SEARCH_MODE_PRINT, 237a59fa508Sjl138328 SEARCH_MODE_DEL 238a59fa508Sjl138328 } search_mode_t; 239a59fa508Sjl138328 240a59fa508Sjl138328 static boolean_t args_to_rtcmd(rtcmd_irep_t *rcip, char **argv, 241a59fa508Sjl138328 char *cmd_string); 2427c478bd9Sstevel@tonic-gate static void bprintf(FILE *fp, int b, char *s); 243a59fa508Sjl138328 static boolean_t compare_rtcmd(rtcmd_irep_t *srch_rt, 244a59fa508Sjl138328 rtcmd_irep_t *file_rt); 2457c478bd9Sstevel@tonic-gate static void delRouteEntry(mib2_ipRouteEntry_t *rp, 2467c478bd9Sstevel@tonic-gate mib2_ipv6RouteEntry_t *rp6, int seqno); 247a59fa508Sjl138328 static void del_rtcmd_irep(rtcmd_irep_t *rcip); 2487c478bd9Sstevel@tonic-gate static void flushroutes(int argc, char *argv[]); 249a59fa508Sjl138328 static boolean_t getaddr(rtcmd_irep_t *rcip, int which, char *s, 250a59fa508Sjl138328 addr_type_t atype); 2517c478bd9Sstevel@tonic-gate static boolean_t in6_getaddr(char *s, struct sockaddr_in6 *sin6, 2527c478bd9Sstevel@tonic-gate int *plenp, struct hostent **hpp); 2537c478bd9Sstevel@tonic-gate static boolean_t in_getaddr(char *s, struct sockaddr_in *sin, 254a59fa508Sjl138328 int *plenp, int which, struct hostent **hpp, addr_type_t atype, 255a59fa508Sjl138328 rtcmd_irep_t *rcip); 2567c478bd9Sstevel@tonic-gate static int in_getprefixlen(char *addr, int max_plen); 2577c478bd9Sstevel@tonic-gate static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 2587c478bd9Sstevel@tonic-gate uchar_t *mask); 259a59fa508Sjl138328 static void inet_makenetandmask(rtcmd_irep_t *rcip, in_addr_t net, 2607c478bd9Sstevel@tonic-gate struct sockaddr_in *sin); 2617c478bd9Sstevel@tonic-gate static in_addr_t inet_makesubnetmask(in_addr_t addr, in_addr_t mask); 262a59fa508Sjl138328 static int keyword(const char *cp); 2637c478bd9Sstevel@tonic-gate static void link_addr(const char *addr, struct sockaddr_dl *sdl); 2647c478bd9Sstevel@tonic-gate static char *link_ntoa(const struct sockaddr_dl *sdl); 2657c478bd9Sstevel@tonic-gate static mib_item_t *mibget(int sd); 2667c478bd9Sstevel@tonic-gate static char *netname(struct sockaddr *sa); 267a59fa508Sjl138328 static int newroute(char **argv); 268a59fa508Sjl138328 static rtcmd_irep_t *new_rtcmd_irep(void); 26945916cd2Sjpk static void pmsg_addrs(const char *cp, size_t len, uint_t addrs); 27045916cd2Sjpk static void pmsg_common(const struct rt_msghdr *rtm, size_t len); 271a59fa508Sjl138328 static void print_getmsg(rtcmd_irep_t *req_rt, 272a59fa508Sjl138328 struct rt_msghdr *rtm, int msglen); 273a59fa508Sjl138328 static void print_rtcmd_short(FILE *to, rtcmd_irep_t *rcip, 274a59fa508Sjl138328 boolean_t gw_good, boolean_t to_saved); 2757c478bd9Sstevel@tonic-gate static void print_rtmsg(struct rt_msghdr *rtm, int msglen); 276aee32e3dScarlsonj static void quit(char *s, int err) __NORETURN; 27745916cd2Sjpk static char *routename(const struct sockaddr *sa); 2787c478bd9Sstevel@tonic-gate static void rtmonitor(int argc, char *argv[]); 279a59fa508Sjl138328 static int rtmsg(rtcmd_irep_t *rcip); 28045916cd2Sjpk static int salen(const struct sockaddr *sa); 281a59fa508Sjl138328 static void save_route(int argc, char **argv, int do_flush); 282a59fa508Sjl138328 static void save_string(char **dst, char *src); 283a59fa508Sjl138328 static int search_rtfile(FILE *fp, FILE *temp_fp, rtcmd_irep_t *rt, 284a59fa508Sjl138328 search_mode_t mode); 285a59fa508Sjl138328 static void set_metric(rtcmd_irep_t *rcip, char *value, int key, 286a59fa508Sjl138328 boolean_t lock); 287a59fa508Sjl138328 static int show_saved_routes(int argc); 2887c478bd9Sstevel@tonic-gate static void sockaddr(char *addr, struct sockaddr *sa); 289a59fa508Sjl138328 static void sodump(su_t *su, char *which); 290a59fa508Sjl138328 static void syntax_arg_missing(char *keyword); 291a59fa508Sjl138328 static void syntax_bad_keyword(char *keyword); 292a59fa508Sjl138328 static void syntax_error(char *err, ...); 2937c478bd9Sstevel@tonic-gate static void usage(char *cp); 294a59fa508Sjl138328 static void write_to_rtfile(FILE *fp, int argc, char **argv); 29545916cd2Sjpk static void pmsg_secattr(const char *, size_t, const char *); 2967c478bd9Sstevel@tonic-gate 297a59fa508Sjl138328 static pid_t pid; 2987c478bd9Sstevel@tonic-gate static int s; 299a59fa508Sjl138328 static boolean_t nflag; 3007c478bd9Sstevel@tonic-gate static int af = AF_INET; 3017c478bd9Sstevel@tonic-gate static boolean_t qflag, tflag; 302a59fa508Sjl138328 static boolean_t verbose; 303a59fa508Sjl138328 static boolean_t debugonly; 3047c478bd9Sstevel@tonic-gate static boolean_t fflag; 305a59fa508Sjl138328 static boolean_t update_table; 306a59fa508Sjl138328 static boolean_t perm_flag; 307a59fa508Sjl138328 static boolean_t early_v6_keyword; 308a59fa508Sjl138328 static char perm_file_sfx[] = "/etc/inet/static_routes"; 309a59fa508Sjl138328 static char *perm_file; 310a59fa508Sjl138328 static char temp_file_sfx[] = "/etc/inet/static_routes.tmp"; 311a59fa508Sjl138328 static char *temp_file; 312a59fa508Sjl138328 static struct in6_addr in6_host_mask = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 313a59fa508Sjl138328 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 314a59fa508Sjl138328 /* 315a59fa508Sjl138328 * WARNING: 316a59fa508Sjl138328 * This next variable indicates whether certain functions exit when an error 317a59fa508Sjl138328 * is detected in the user input. Currently, exit_on_error is only set false 318a59fa508Sjl138328 * in search_rtfile(), when argument are being parsed. Only those functions 319a59fa508Sjl138328 * used by search_rtfile() to parse its arguments are designed to work in 320a59fa508Sjl138328 * both modes. Take particular care in setting this false to ensure that any 321a59fa508Sjl138328 * functions you call that might act on this flag properly return errors when 322a59fa508Sjl138328 * exit_on_error is false. 323a59fa508Sjl138328 */ 324a59fa508Sjl138328 static int exit_on_error = B_TRUE; 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate static struct { 3277c478bd9Sstevel@tonic-gate struct rt_msghdr m_rtm; 32845916cd2Sjpk char m_space[BUF_SIZE]; 3297c478bd9Sstevel@tonic-gate } m_rtmsg; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate /* 3327c478bd9Sstevel@tonic-gate * Sizes of data structures extracted from the base mib. 3337c478bd9Sstevel@tonic-gate * This allows the size of the tables entries to grow while preserving 3347c478bd9Sstevel@tonic-gate * binary compatibility. 3357c478bd9Sstevel@tonic-gate */ 3367c478bd9Sstevel@tonic-gate static int ipRouteEntrySize; 3377c478bd9Sstevel@tonic-gate static int ipv6RouteEntrySize; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate #define ROUNDUP_LONG(a) \ 3407c478bd9Sstevel@tonic-gate ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long)) 3417c478bd9Sstevel@tonic-gate #define ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n))) 3427c478bd9Sstevel@tonic-gate #define C(x) ((x) & 0xff) 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate /* 3457c478bd9Sstevel@tonic-gate * return values from in_getprefixlen() 3467c478bd9Sstevel@tonic-gate */ 3477c478bd9Sstevel@tonic-gate #define BAD_ADDR -1 /* prefix is invalid */ 3487c478bd9Sstevel@tonic-gate #define NO_PREFIX -2 /* no prefix was found */ 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate void 3517c478bd9Sstevel@tonic-gate usage(char *cp) 3527c478bd9Sstevel@tonic-gate { 353a59fa508Sjl138328 if (cp != NULL) { 3547c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: botched keyword: %s\n"), 3557c478bd9Sstevel@tonic-gate cp); 356a59fa508Sjl138328 } 357a59fa508Sjl138328 (void) fprintf(stderr, gettext("usage: route [ -fnpqv ] " 358a59fa508Sjl138328 "[ -R <root-dir> ] cmd [[ -<qualifers> ] args ]\n")); 3597c478bd9Sstevel@tonic-gate exit(1); 3607c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 363a59fa508Sjl138328 /*PRINTFLIKE1*/ 364a59fa508Sjl138328 void 365a59fa508Sjl138328 syntax_error(char *err, ...) 366a59fa508Sjl138328 { 367a59fa508Sjl138328 va_list args; 368a59fa508Sjl138328 369a59fa508Sjl138328 if (exit_on_error) { 370a59fa508Sjl138328 va_start(args, err); 371a59fa508Sjl138328 (void) vfprintf(stderr, err, args); 372a59fa508Sjl138328 va_end(args); 373a59fa508Sjl138328 exit(1); 374a59fa508Sjl138328 } 375a59fa508Sjl138328 /* NOTREACHED */ 376a59fa508Sjl138328 } 377a59fa508Sjl138328 378a59fa508Sjl138328 void 379a59fa508Sjl138328 syntax_bad_keyword(char *keyword) 380a59fa508Sjl138328 { 381a59fa508Sjl138328 syntax_error(gettext("route: botched keyword: %s\n"), keyword); 382a59fa508Sjl138328 } 383a59fa508Sjl138328 384a59fa508Sjl138328 void 385a59fa508Sjl138328 syntax_arg_missing(char *keyword) 386a59fa508Sjl138328 { 387a59fa508Sjl138328 syntax_error(gettext("route: argument required following keyword %s\n"), 388a59fa508Sjl138328 keyword); 389a59fa508Sjl138328 } 390a59fa508Sjl138328 3917c478bd9Sstevel@tonic-gate void 3927c478bd9Sstevel@tonic-gate quit(char *s, int sverrno) 3937c478bd9Sstevel@tonic-gate { 3947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "route: "); 3957c478bd9Sstevel@tonic-gate if (s != NULL) 3967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", s); 3977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", strerror(sverrno)); 3987c478bd9Sstevel@tonic-gate exit(sverrno); 3997c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate int 4037c478bd9Sstevel@tonic-gate main(int argc, char **argv) 4047c478bd9Sstevel@tonic-gate { 4057c478bd9Sstevel@tonic-gate extern int optind; 406a59fa508Sjl138328 extern char *optarg; 4077c478bd9Sstevel@tonic-gate int ch; 408a59fa508Sjl138328 int rval; 409a59fa508Sjl138328 size_t size; 410a59fa508Sjl138328 const char *root_dir = NULL; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 4157c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 4167c478bd9Sstevel@tonic-gate #endif 4177c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate if (argc < 2) 42045916cd2Sjpk usage(NULL); 4217c478bd9Sstevel@tonic-gate 422a59fa508Sjl138328 while ((ch = getopt(argc, argv, "R:nqdtvfp")) != EOF) { 4237c478bd9Sstevel@tonic-gate switch (ch) { 4247c478bd9Sstevel@tonic-gate case 'n': 4257c478bd9Sstevel@tonic-gate nflag = B_TRUE; 4267c478bd9Sstevel@tonic-gate break; 4277c478bd9Sstevel@tonic-gate case 'q': 4287c478bd9Sstevel@tonic-gate qflag = B_TRUE; 4297c478bd9Sstevel@tonic-gate break; 4307c478bd9Sstevel@tonic-gate case 'v': 4317c478bd9Sstevel@tonic-gate verbose = B_TRUE; 4327c478bd9Sstevel@tonic-gate break; 4337c478bd9Sstevel@tonic-gate case 't': 4347c478bd9Sstevel@tonic-gate tflag = B_TRUE; 4357c478bd9Sstevel@tonic-gate break; 4367c478bd9Sstevel@tonic-gate case 'd': 4377c478bd9Sstevel@tonic-gate debugonly = B_TRUE; 4387c478bd9Sstevel@tonic-gate break; 4397c478bd9Sstevel@tonic-gate case 'f': 4407c478bd9Sstevel@tonic-gate fflag = B_TRUE; 4417c478bd9Sstevel@tonic-gate break; 442a59fa508Sjl138328 case 'p': 443a59fa508Sjl138328 perm_flag = B_TRUE; 444a59fa508Sjl138328 break; 445a59fa508Sjl138328 case 'R': 446a59fa508Sjl138328 root_dir = optarg; 447a59fa508Sjl138328 break; 4487c478bd9Sstevel@tonic-gate case '?': 4497c478bd9Sstevel@tonic-gate default: 45045916cd2Sjpk usage(NULL); 4517c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate argc -= optind; 4557c478bd9Sstevel@tonic-gate argv += optind; 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate pid = getpid(); 4587c478bd9Sstevel@tonic-gate if (tflag) 4597c478bd9Sstevel@tonic-gate s = open("/dev/null", O_WRONLY); 4607c478bd9Sstevel@tonic-gate else 4617c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, 0); 4627c478bd9Sstevel@tonic-gate if (s < 0) 4637c478bd9Sstevel@tonic-gate quit("socket", errno); 464a59fa508Sjl138328 465a59fa508Sjl138328 /* 466a59fa508Sjl138328 * Handle the -p and -R flags. The -R flag only applies 467a59fa508Sjl138328 * when the -p flag is set. 468a59fa508Sjl138328 */ 469a59fa508Sjl138328 if (root_dir == NULL) { 470a59fa508Sjl138328 perm_file = perm_file_sfx; 471a59fa508Sjl138328 temp_file = temp_file_sfx; 472a59fa508Sjl138328 } else { 473a59fa508Sjl138328 size = strlen(root_dir) + sizeof (perm_file_sfx); 474a59fa508Sjl138328 perm_file = malloc(size); 475a59fa508Sjl138328 if (perm_file == NULL) 476a59fa508Sjl138328 quit("malloc", errno); 477a59fa508Sjl138328 (void) snprintf(perm_file, size, "%s%s", root_dir, 478a59fa508Sjl138328 perm_file_sfx); 479a59fa508Sjl138328 size = strlen(root_dir) + sizeof (temp_file_sfx); 480a59fa508Sjl138328 temp_file = malloc(size); 481a59fa508Sjl138328 if (temp_file == NULL) 482a59fa508Sjl138328 quit("malloc", errno); 483a59fa508Sjl138328 (void) snprintf(temp_file, size, "%s%s", root_dir, 484a59fa508Sjl138328 temp_file_sfx); 485a59fa508Sjl138328 } 486a59fa508Sjl138328 /* 487a59fa508Sjl138328 * Whether or not to act on the routing table. The only time the 488a59fa508Sjl138328 * routing table is not modified is when both -p and -R are present. 489a59fa508Sjl138328 */ 490a59fa508Sjl138328 update_table = (!perm_flag || root_dir == NULL); 491a59fa508Sjl138328 if (tflag) 492a59fa508Sjl138328 perm_flag = 0; 493a59fa508Sjl138328 4947c478bd9Sstevel@tonic-gate if (fflag) { 4957c478bd9Sstevel@tonic-gate /* 4967c478bd9Sstevel@tonic-gate * Accept an address family keyword after the -f. Since the 4977c478bd9Sstevel@tonic-gate * default address family is AF_INET, reassign af only for the 4987c478bd9Sstevel@tonic-gate * other valid address families. 4997c478bd9Sstevel@tonic-gate */ 5007c478bd9Sstevel@tonic-gate if (*argv != NULL) { 501a59fa508Sjl138328 switch (keyword(*argv)) { 5027c478bd9Sstevel@tonic-gate case K_INET6: 5037c478bd9Sstevel@tonic-gate af = AF_INET6; 504a59fa508Sjl138328 early_v6_keyword = B_TRUE; 505a59fa508Sjl138328 /* fallthrough */ 506a59fa508Sjl138328 case K_INET: 5077c478bd9Sstevel@tonic-gate /* Skip over the address family parameter. */ 5087c478bd9Sstevel@tonic-gate argc--; 5097c478bd9Sstevel@tonic-gate argv++; 5107c478bd9Sstevel@tonic-gate break; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate flushroutes(0, NULL); 5147c478bd9Sstevel@tonic-gate } 515a59fa508Sjl138328 5167c478bd9Sstevel@tonic-gate if (*argv != NULL) { 5177c478bd9Sstevel@tonic-gate switch (keyword(*argv)) { 5187c478bd9Sstevel@tonic-gate case K_GET: 5197c478bd9Sstevel@tonic-gate case K_CHANGE: 5207c478bd9Sstevel@tonic-gate case K_ADD: 5217c478bd9Sstevel@tonic-gate case K_DELETE: 522a59fa508Sjl138328 rval = 0; 523a59fa508Sjl138328 if (update_table) { 524a59fa508Sjl138328 rval = newroute(argv); 525a59fa508Sjl138328 } 526a59fa508Sjl138328 if (perm_flag && (rval == 0 || rval == EEXIST || 527a59fa508Sjl138328 rval == ESRCH)) { 528a59fa508Sjl138328 save_route(argc, argv, B_FALSE); 529a59fa508Sjl138328 return (0); 530a59fa508Sjl138328 } 531a59fa508Sjl138328 return (rval); 532a59fa508Sjl138328 case K_SHOW: 533a59fa508Sjl138328 if (perm_flag) { 534a59fa508Sjl138328 return (show_saved_routes(argc)); 535a59fa508Sjl138328 } else { 536a59fa508Sjl138328 syntax_error(gettext( 537a59fa508Sjl138328 "route: show command requires -p\n")); 538a59fa508Sjl138328 } 539a59fa508Sjl138328 /* NOTREACHED */ 5407c478bd9Sstevel@tonic-gate case K_MONITOR: 5417c478bd9Sstevel@tonic-gate rtmonitor(argc, argv); 5427c478bd9Sstevel@tonic-gate /* NOTREACHED */ 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate case K_FLUSH: 5457c478bd9Sstevel@tonic-gate flushroutes(argc, argv); 546a59fa508Sjl138328 return (0); 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate if (!fflag) 5507c478bd9Sstevel@tonic-gate usage(*argv); 5517c478bd9Sstevel@tonic-gate return (0); 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /* 5557c478bd9Sstevel@tonic-gate * Purge all entries in the routing tables not 5567c478bd9Sstevel@tonic-gate * associated with network interfaces. 5577c478bd9Sstevel@tonic-gate */ 5587c478bd9Sstevel@tonic-gate void 5597c478bd9Sstevel@tonic-gate flushroutes(int argc, char *argv[]) 5607c478bd9Sstevel@tonic-gate { 5617c478bd9Sstevel@tonic-gate int seqno; 5627c478bd9Sstevel@tonic-gate int sd; /* mib stream */ 5637c478bd9Sstevel@tonic-gate mib_item_t *item; 5647c478bd9Sstevel@tonic-gate mib2_ipRouteEntry_t *rp; 5657c478bd9Sstevel@tonic-gate mib2_ipv6RouteEntry_t *rp6; 5667c478bd9Sstevel@tonic-gate int oerrno; 5677c478bd9Sstevel@tonic-gate int off = 0; 5687c478bd9Sstevel@tonic-gate int on = 1; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate if (argc > 1) { 5717c478bd9Sstevel@tonic-gate argv++; 5727c478bd9Sstevel@tonic-gate if (argc == 2 && **argv == '-') { 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * The address family (preceded by a dash) may be used 5757c478bd9Sstevel@tonic-gate * to flush the routes of that particular family. 5767c478bd9Sstevel@tonic-gate */ 5777c478bd9Sstevel@tonic-gate switch (keyword(*argv + 1)) { 5787c478bd9Sstevel@tonic-gate case K_INET: 5797c478bd9Sstevel@tonic-gate af = AF_INET; 5807c478bd9Sstevel@tonic-gate break; 5817c478bd9Sstevel@tonic-gate case K_LINK: 5827c478bd9Sstevel@tonic-gate af = AF_LINK; 5837c478bd9Sstevel@tonic-gate break; 5847c478bd9Sstevel@tonic-gate case K_INET6: 5857c478bd9Sstevel@tonic-gate af = AF_INET6; 5867c478bd9Sstevel@tonic-gate break; 5877c478bd9Sstevel@tonic-gate default: 5887c478bd9Sstevel@tonic-gate usage(*argv); 5897c478bd9Sstevel@tonic-gate /* NOTREACHED */ 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate } else { 5927c478bd9Sstevel@tonic-gate usage(*argv); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate } 595a59fa508Sjl138328 if (perm_flag) { 596a59fa508Sjl138328 /* This flushes the persistent route file */ 597a59fa508Sjl138328 save_route(0, NULL, B_TRUE); 598a59fa508Sjl138328 } 599a59fa508Sjl138328 if (!update_table) { 600a59fa508Sjl138328 return; 601a59fa508Sjl138328 } 602a59fa508Sjl138328 603a59fa508Sjl138328 if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off, 604a59fa508Sjl138328 sizeof (off)) < 0) 605a59fa508Sjl138328 quit("setsockopt", errno); 606a59fa508Sjl138328 6077c478bd9Sstevel@tonic-gate sd = open("/dev/ip", O_RDWR); 6087c478bd9Sstevel@tonic-gate oerrno = errno; 6097c478bd9Sstevel@tonic-gate if (sd < 0) { 6107c478bd9Sstevel@tonic-gate switch (errno) { 6117c478bd9Sstevel@tonic-gate case EACCES: 6127c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6137c478bd9Sstevel@tonic-gate gettext("route: flush: insufficient privileges\n")); 6147c478bd9Sstevel@tonic-gate exit(oerrno); 6157c478bd9Sstevel@tonic-gate /* NOTREACHED */ 6167c478bd9Sstevel@tonic-gate default: 6177c478bd9Sstevel@tonic-gate quit(gettext("can't open mib stream"), oerrno); 6187c478bd9Sstevel@tonic-gate /* NOTREACHED */ 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate if ((item = mibget(sd)) == NULL) 6227c478bd9Sstevel@tonic-gate quit("mibget", errno); 6237c478bd9Sstevel@tonic-gate if (verbose) { 6247c478bd9Sstevel@tonic-gate (void) printf("Examining routing table from " 6257c478bd9Sstevel@tonic-gate "T_SVR4_OPTMGMT_REQ\n"); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate seqno = 0; /* ??? */ 6287c478bd9Sstevel@tonic-gate switch (af) { 6297c478bd9Sstevel@tonic-gate case AF_INET: 6307c478bd9Sstevel@tonic-gate /* Extract ipRouteEntrySize */ 6317c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 6327c478bd9Sstevel@tonic-gate if (item->mib_id != 0) 6337c478bd9Sstevel@tonic-gate continue; 6347c478bd9Sstevel@tonic-gate if (item->group == MIB2_IP) { 6357c478bd9Sstevel@tonic-gate ipRouteEntrySize = 6367c478bd9Sstevel@tonic-gate ((mib2_ip_t *)item->valp)->ipRouteEntrySize; 6377c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(ipRouteEntrySize, 6387c478bd9Sstevel@tonic-gate sizeof (mib2_ipRouteEntry_t *))); 6397c478bd9Sstevel@tonic-gate break; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate if (ipRouteEntrySize == 0) { 6437c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6447c478bd9Sstevel@tonic-gate gettext("ipRouteEntrySize can't be determined.\n")); 6457c478bd9Sstevel@tonic-gate exit(1); 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 6487c478bd9Sstevel@tonic-gate /* 6497c478bd9Sstevel@tonic-gate * skip all the other trash that comes up the mib stream 6507c478bd9Sstevel@tonic-gate */ 6517c478bd9Sstevel@tonic-gate if (item->group != MIB2_IP || 6527c478bd9Sstevel@tonic-gate item->mib_id != MIB2_IP_ROUTE) 6537c478bd9Sstevel@tonic-gate continue; 6547c478bd9Sstevel@tonic-gate for (rp = (mib2_ipRouteEntry_t *)item->valp; 6557c478bd9Sstevel@tonic-gate (char *)rp < (char *)item->valp + item->length; 6567c478bd9Sstevel@tonic-gate /* LINTED */ 6577c478bd9Sstevel@tonic-gate rp = (mib2_ipRouteEntry_t *) 6587c478bd9Sstevel@tonic-gate ((char *)rp + ipRouteEntrySize)) { 6597c478bd9Sstevel@tonic-gate delRouteEntry(rp, NULL, seqno); 6607c478bd9Sstevel@tonic-gate seqno++; 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate break; 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate break; 6657c478bd9Sstevel@tonic-gate case AF_INET6: 6667c478bd9Sstevel@tonic-gate /* Extract ipv6RouteEntrySize */ 6677c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 6687c478bd9Sstevel@tonic-gate if (item->mib_id != 0) 6697c478bd9Sstevel@tonic-gate continue; 6707c478bd9Sstevel@tonic-gate if (item->group == MIB2_IP6) { 6717c478bd9Sstevel@tonic-gate ipv6RouteEntrySize = 6727c478bd9Sstevel@tonic-gate ((mib2_ipv6IfStatsEntry_t *)item->valp)-> 6737c478bd9Sstevel@tonic-gate ipv6RouteEntrySize; 6747c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(ipv6RouteEntrySize, 6757c478bd9Sstevel@tonic-gate sizeof (mib2_ipv6RouteEntry_t *))); 6767c478bd9Sstevel@tonic-gate break; 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate if (ipv6RouteEntrySize == 0) { 6807c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6817c478bd9Sstevel@tonic-gate "ipv6RouteEntrySize cannot be determined.\n")); 6827c478bd9Sstevel@tonic-gate exit(1); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 6857c478bd9Sstevel@tonic-gate /* 6867c478bd9Sstevel@tonic-gate * skip all the other trash that comes up the mib stream 6877c478bd9Sstevel@tonic-gate */ 6887c478bd9Sstevel@tonic-gate if (item->group != MIB2_IP6 || 6897c478bd9Sstevel@tonic-gate item->mib_id != MIB2_IP6_ROUTE) 6907c478bd9Sstevel@tonic-gate continue; 6917c478bd9Sstevel@tonic-gate for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp; 6927c478bd9Sstevel@tonic-gate (char *)rp6 < (char *)item->valp + item->length; 6937c478bd9Sstevel@tonic-gate /* LINTED */ 6947c478bd9Sstevel@tonic-gate rp6 = (mib2_ipv6RouteEntry_t *) 6957c478bd9Sstevel@tonic-gate ((char *)rp6 + ipv6RouteEntrySize)) { 6967c478bd9Sstevel@tonic-gate delRouteEntry(NULL, rp6, seqno); 6977c478bd9Sstevel@tonic-gate seqno++; 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate break; 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate break; 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, 7057c478bd9Sstevel@tonic-gate sizeof (on)) < 0) 7067c478bd9Sstevel@tonic-gate quit("setsockopt", errno); 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /* 7107c478bd9Sstevel@tonic-gate * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or 7117c478bd9Sstevel@tonic-gate * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in 7127c478bd9Sstevel@tonic-gate * order to facilitate the flushing of RTF_GATEWAY routes. 7137c478bd9Sstevel@tonic-gate */ 7147c478bd9Sstevel@tonic-gate static void 7157c478bd9Sstevel@tonic-gate delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno) 7167c478bd9Sstevel@tonic-gate { 7177c478bd9Sstevel@tonic-gate char *cp; 7187c478bd9Sstevel@tonic-gate int ire_type; 7197c478bd9Sstevel@tonic-gate int rlen; 7207c478bd9Sstevel@tonic-gate struct rt_msghdr *rtm; 7217c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 7227c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 7237c478bd9Sstevel@tonic-gate int slen; 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate if (rp != NULL) 7267c478bd9Sstevel@tonic-gate ire_type = rp->ipRouteInfo.re_ire_type; 7277c478bd9Sstevel@tonic-gate else 7287c478bd9Sstevel@tonic-gate ire_type = rp6->ipv6RouteInfo.re_ire_type; 7297c478bd9Sstevel@tonic-gate if (ire_type != IRE_DEFAULT && 7307c478bd9Sstevel@tonic-gate ire_type != IRE_PREFIX && 7317c478bd9Sstevel@tonic-gate ire_type != IRE_HOST && 7327c478bd9Sstevel@tonic-gate ire_type != IRE_HOST_REDIRECT) 7337c478bd9Sstevel@tonic-gate return; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate rtm = &m_rtmsg.m_rtm; 7367c478bd9Sstevel@tonic-gate (void) memset(rtm, 0, sizeof (m_rtmsg)); 7377c478bd9Sstevel@tonic-gate rtm->rtm_type = RTM_DELETE; 7387c478bd9Sstevel@tonic-gate rtm->rtm_seq = seqno; 7397c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_GATEWAY; 7407c478bd9Sstevel@tonic-gate rtm->rtm_version = RTM_VERSION; 7417c478bd9Sstevel@tonic-gate rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 7427c478bd9Sstevel@tonic-gate cp = m_rtmsg.m_space; 7437c478bd9Sstevel@tonic-gate if (rp != NULL) { 7447c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in); 7457c478bd9Sstevel@tonic-gate if (rp->ipRouteMask == IP_HOST_MASK) 7467c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_HOST; 7477c478bd9Sstevel@tonic-gate (void) memset(&sin, 0, slen); 7487c478bd9Sstevel@tonic-gate sin.sin_family = AF_INET; 7497c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteDest; 7507c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 7517c478bd9Sstevel@tonic-gate cp += slen; 7527c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteNextHop; 7537c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 7547c478bd9Sstevel@tonic-gate cp += slen; 7557c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteMask; 7567c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 7577c478bd9Sstevel@tonic-gate cp += slen; 7587c478bd9Sstevel@tonic-gate } else { 7597c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in6); 7607c478bd9Sstevel@tonic-gate if (rp6->ipv6RoutePfxLength == IPV6_ABITS) 7617c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_HOST; 7627c478bd9Sstevel@tonic-gate (void) memset(&sin6, 0, slen); 7637c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 7647c478bd9Sstevel@tonic-gate sin6.sin6_addr = rp6->ipv6RouteDest; 7657c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 7667c478bd9Sstevel@tonic-gate cp += slen; 7677c478bd9Sstevel@tonic-gate sin6.sin6_addr = rp6->ipv6RouteNextHop; 7687c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 7697c478bd9Sstevel@tonic-gate cp += slen; 7707c478bd9Sstevel@tonic-gate (void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr)); 7717c478bd9Sstevel@tonic-gate (void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS, 7727c478bd9Sstevel@tonic-gate (uchar_t *)&sin6.sin6_addr.s6_addr); 7737c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 7747c478bd9Sstevel@tonic-gate cp += slen; 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate rtm->rtm_msglen = cp - (char *)&m_rtmsg; 7777c478bd9Sstevel@tonic-gate if (debugonly) { 7787c478bd9Sstevel@tonic-gate /* 7797c478bd9Sstevel@tonic-gate * In debugonly mode, the routing socket message to delete the 7807c478bd9Sstevel@tonic-gate * current entry is not actually sent. However if verbose is 7817c478bd9Sstevel@tonic-gate * also set, the routing socket message that would have been 7827c478bd9Sstevel@tonic-gate * is printed. 7837c478bd9Sstevel@tonic-gate */ 7847c478bd9Sstevel@tonic-gate if (verbose) 7857c478bd9Sstevel@tonic-gate print_rtmsg(rtm, rtm->rtm_msglen); 7867c478bd9Sstevel@tonic-gate return; 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen); 7907c478bd9Sstevel@tonic-gate if (rlen < (int)rtm->rtm_msglen) { 7917c478bd9Sstevel@tonic-gate if (rlen < 0) { 7927c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7937c478bd9Sstevel@tonic-gate gettext("route: write to routing socket: %s\n"), 7947c478bd9Sstevel@tonic-gate strerror(errno)); 7957c478bd9Sstevel@tonic-gate } else { 7967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: write to " 7977c478bd9Sstevel@tonic-gate "routing socket got only %d for rlen\n"), rlen); 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate return; 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate if (qflag) { 8027c478bd9Sstevel@tonic-gate /* 8037c478bd9Sstevel@tonic-gate * In quiet mode, nothing is printed at all (unless the write() 8047c478bd9Sstevel@tonic-gate * itself failed. 8057c478bd9Sstevel@tonic-gate */ 8067c478bd9Sstevel@tonic-gate return; 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate if (verbose) { 8097c478bd9Sstevel@tonic-gate print_rtmsg(rtm, rlen); 8107c478bd9Sstevel@tonic-gate } else { 8117c478bd9Sstevel@tonic-gate struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate (void) printf("%-20.20s ", 8147c478bd9Sstevel@tonic-gate rtm->rtm_flags & RTF_HOST ? routename(sa) : 8157c478bd9Sstevel@tonic-gate netname(sa)); 8167c478bd9Sstevel@tonic-gate /* LINTED */ 8177c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)(salen(sa) + (char *)sa); 8187c478bd9Sstevel@tonic-gate (void) printf("%-20.20s ", routename(sa)); 8197c478bd9Sstevel@tonic-gate (void) printf("done\n"); 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* 8247c478bd9Sstevel@tonic-gate * Return the name of the host whose address is given. 8257c478bd9Sstevel@tonic-gate */ 8267c478bd9Sstevel@tonic-gate char * 82745916cd2Sjpk routename(const struct sockaddr *sa) 8287c478bd9Sstevel@tonic-gate { 8297c478bd9Sstevel@tonic-gate char *cp; 8307c478bd9Sstevel@tonic-gate static char line[MAXHOSTNAMELEN + 1]; 8317c478bd9Sstevel@tonic-gate struct hostent *hp = NULL; 8327c478bd9Sstevel@tonic-gate static char domain[MAXHOSTNAMELEN + 1]; 8337c478bd9Sstevel@tonic-gate static boolean_t first = B_TRUE; 8347c478bd9Sstevel@tonic-gate struct in_addr in; 8357c478bd9Sstevel@tonic-gate struct in6_addr in6; 8367c478bd9Sstevel@tonic-gate int error_num; 8377c478bd9Sstevel@tonic-gate ushort_t *s; 8387c478bd9Sstevel@tonic-gate ushort_t *slim; 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate if (first) { 8417c478bd9Sstevel@tonic-gate first = B_FALSE; 8427c478bd9Sstevel@tonic-gate if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 8437c478bd9Sstevel@tonic-gate (cp = strchr(domain, '.'))) 8447c478bd9Sstevel@tonic-gate (void) strcpy(domain, cp + 1); 8457c478bd9Sstevel@tonic-gate else 8467c478bd9Sstevel@tonic-gate domain[0] = 0; 8477c478bd9Sstevel@tonic-gate } 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate if (salen(sa) == 0) { 8507c478bd9Sstevel@tonic-gate (void) strcpy(line, "default"); 8517c478bd9Sstevel@tonic-gate return (line); 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate case AF_INET: 8567c478bd9Sstevel@tonic-gate /* LINTED */ 8577c478bd9Sstevel@tonic-gate in = ((struct sockaddr_in *)sa)->sin_addr; 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate cp = NULL; 8607c478bd9Sstevel@tonic-gate if (in.s_addr == INADDR_ANY) 8617c478bd9Sstevel@tonic-gate cp = "default"; 8627c478bd9Sstevel@tonic-gate if (cp == NULL && !nflag) { 8637c478bd9Sstevel@tonic-gate hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 8647c478bd9Sstevel@tonic-gate AF_INET); 8657c478bd9Sstevel@tonic-gate if (hp != NULL) { 8667c478bd9Sstevel@tonic-gate if (((cp = strchr(hp->h_name, '.')) != NULL) && 8677c478bd9Sstevel@tonic-gate (strcmp(cp + 1, domain) == 0)) 8687c478bd9Sstevel@tonic-gate *cp = 0; 8697c478bd9Sstevel@tonic-gate cp = hp->h_name; 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate if (cp != NULL) { 8737c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 8747c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 8757c478bd9Sstevel@tonic-gate } else { 8767c478bd9Sstevel@tonic-gate in.s_addr = ntohl(in.s_addr); 8777c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 8787c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8), 8797c478bd9Sstevel@tonic-gate C(in.s_addr)); 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate break; 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate case AF_LINK: 8847c478bd9Sstevel@tonic-gate return (link_ntoa((struct sockaddr_dl *)sa)); 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate case AF_INET6: 8877c478bd9Sstevel@tonic-gate /* LINTED */ 8887c478bd9Sstevel@tonic-gate in6 = ((struct sockaddr_in6 *)sa)->sin6_addr; 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate cp = NULL; 8917c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&in6)) 8927c478bd9Sstevel@tonic-gate cp = "default"; 8937c478bd9Sstevel@tonic-gate if (cp == NULL && !nflag) { 8947c478bd9Sstevel@tonic-gate hp = getipnodebyaddr((char *)&in6, 8957c478bd9Sstevel@tonic-gate sizeof (struct in6_addr), AF_INET6, &error_num); 8967c478bd9Sstevel@tonic-gate if (hp != NULL) { 8977c478bd9Sstevel@tonic-gate if (((cp = strchr(hp->h_name, '.')) != NULL) && 8987c478bd9Sstevel@tonic-gate (strcmp(cp + 1, domain) == 0)) 8997c478bd9Sstevel@tonic-gate *cp = 0; 9007c478bd9Sstevel@tonic-gate cp = hp->h_name; 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate if (cp != NULL) { 9047c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 9057c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 9067c478bd9Sstevel@tonic-gate } else { 9077c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&in6, line, 9087c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN); 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate if (hp != NULL) 9117c478bd9Sstevel@tonic-gate freehostent(hp); 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate break; 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate default: 9167c478bd9Sstevel@tonic-gate s = (ushort_t *)sa; 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate slim = s + ((salen(sa) + 1) >> 1); 9197c478bd9Sstevel@tonic-gate cp = line + sprintf(line, "(%d)", sa->sa_family); 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate while (++s < slim) /* start with sa->sa_data */ 9227c478bd9Sstevel@tonic-gate cp += sprintf(cp, " %x", *s); 9237c478bd9Sstevel@tonic-gate break; 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate return (line); 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate /* 9297c478bd9Sstevel@tonic-gate * Return the name of the network whose address is given. 9307c478bd9Sstevel@tonic-gate * The address is assumed to be that of a net or subnet, not a host. 9317c478bd9Sstevel@tonic-gate */ 9327c478bd9Sstevel@tonic-gate static char * 9337c478bd9Sstevel@tonic-gate netname(struct sockaddr *sa) 9347c478bd9Sstevel@tonic-gate { 9357c478bd9Sstevel@tonic-gate char *cp = NULL; 9367c478bd9Sstevel@tonic-gate static char line[MAXHOSTNAMELEN + 1]; 9377c478bd9Sstevel@tonic-gate struct netent *np; 9387c478bd9Sstevel@tonic-gate in_addr_t net, mask; 9397c478bd9Sstevel@tonic-gate int subnetshift; 9407c478bd9Sstevel@tonic-gate struct in_addr in; 9417c478bd9Sstevel@tonic-gate ushort_t *s; 9427c478bd9Sstevel@tonic-gate ushort_t *slim; 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate case AF_INET: 9477c478bd9Sstevel@tonic-gate /* LINTED */ 9487c478bd9Sstevel@tonic-gate in = ((struct sockaddr_in *)sa)->sin_addr; 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate in.s_addr = ntohl(in.s_addr); 9517c478bd9Sstevel@tonic-gate if (in.s_addr == INADDR_ANY) { 9527c478bd9Sstevel@tonic-gate cp = "default"; 9537c478bd9Sstevel@tonic-gate } else if (!nflag) { 9547c478bd9Sstevel@tonic-gate if (IN_CLASSA(in.s_addr)) { 9557c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 9567c478bd9Sstevel@tonic-gate subnetshift = 8; 9577c478bd9Sstevel@tonic-gate } else if (IN_CLASSB(in.s_addr)) { 9587c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 9597c478bd9Sstevel@tonic-gate subnetshift = 8; 9607c478bd9Sstevel@tonic-gate } else { 9617c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 9627c478bd9Sstevel@tonic-gate subnetshift = 4; 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate /* 9657c478bd9Sstevel@tonic-gate * If there are more bits than the standard mask 9667c478bd9Sstevel@tonic-gate * would suggest, subnets must be in use. 9677c478bd9Sstevel@tonic-gate * Guess at the subnet mask, assuming reasonable 9687c478bd9Sstevel@tonic-gate * width subnet fields. 9697c478bd9Sstevel@tonic-gate */ 9707c478bd9Sstevel@tonic-gate while (in.s_addr &~ mask) 9717c478bd9Sstevel@tonic-gate mask = (long)mask >> subnetshift; 9727c478bd9Sstevel@tonic-gate net = in.s_addr & mask; 9737c478bd9Sstevel@tonic-gate while ((mask & 1) == 0) 9747c478bd9Sstevel@tonic-gate mask >>= 1, net >>= 1; 9757c478bd9Sstevel@tonic-gate np = getnetbyaddr(net, AF_INET); 9767c478bd9Sstevel@tonic-gate if (np != NULL) 9777c478bd9Sstevel@tonic-gate cp = np->n_name; 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate if (cp != NULL) { 9807c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 9817c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 9827c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xffffff) == 0) { 9837c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u", C(in.s_addr >> 24)); 9847c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xffff) == 0) { 9857c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 9867c478bd9Sstevel@tonic-gate C(in.s_addr >> 16)); 9877c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xff) == 0) { 9887c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 9897c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8)); 9907c478bd9Sstevel@tonic-gate } else { 9917c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 9927c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8), 9937c478bd9Sstevel@tonic-gate C(in.s_addr)); 9947c478bd9Sstevel@tonic-gate } 9957c478bd9Sstevel@tonic-gate break; 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate case AF_LINK: 9987c478bd9Sstevel@tonic-gate return (link_ntoa((struct sockaddr_dl *)sa)); 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate case AF_INET6: 10017c478bd9Sstevel@tonic-gate return (routename(sa)); 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate default: 10047c478bd9Sstevel@tonic-gate /* LINTED */ 10057c478bd9Sstevel@tonic-gate s = (ushort_t *)sa->sa_data; 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate slim = s + ((salen(sa) + 1) >> 1); 10087c478bd9Sstevel@tonic-gate cp = line + sprintf(line, "af %d:", sa->sa_family); 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate while (s < slim) 10117c478bd9Sstevel@tonic-gate cp += sprintf(cp, " %x", *s++); 10127c478bd9Sstevel@tonic-gate break; 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate return (line); 10157c478bd9Sstevel@tonic-gate } 10167c478bd9Sstevel@tonic-gate 1017a59fa508Sjl138328 /* 1018a59fa508Sjl138328 * Initialize a new structure. Keep in mind that ri_dst_str, ri_gate_str and 1019a59fa508Sjl138328 * ri_ifp_str will be freed by det_rtcmd_irep, so they should either be NULL 1020a59fa508Sjl138328 * or point to dynamically allocated memory. 1021a59fa508Sjl138328 */ 1022a59fa508Sjl138328 rtcmd_irep_t * 1023a59fa508Sjl138328 new_rtcmd_irep(void) 1024a59fa508Sjl138328 { 1025a59fa508Sjl138328 rtcmd_irep_t *rcip; 1026a59fa508Sjl138328 1027a59fa508Sjl138328 rcip = calloc(1, sizeof (rtcmd_irep_t)); 1028a59fa508Sjl138328 if (rcip == NULL) { 1029a59fa508Sjl138328 quit("calloc", errno); 1030a59fa508Sjl138328 } 1031a59fa508Sjl138328 rcip->ri_af = af; 1032a59fa508Sjl138328 rcip->ri_flags = RTF_STATIC; 1033a59fa508Sjl138328 return (rcip); 1034a59fa508Sjl138328 } 1035a59fa508Sjl138328 10367c478bd9Sstevel@tonic-gate void 1037a59fa508Sjl138328 del_rtcmd_irep(rtcmd_irep_t *rcip) 1038a59fa508Sjl138328 { 1039a59fa508Sjl138328 free(rcip->ri_dest_str); 1040a59fa508Sjl138328 free(rcip->ri_gate_str); 1041a59fa508Sjl138328 free(rcip->ri_ifp_str); 1042b2a92f83Sdg199075 /* 1043b2a92f83Sdg199075 * IPv6 host entries come from getipnodebyname, which dynamically 1044b2a92f83Sdg199075 * allocates memory. IPv4 host entries come from gethostbyname, which 1045b2a92f83Sdg199075 * returns static memory and cannot be freed with freehostent. 1046b2a92f83Sdg199075 */ 1047b2a92f83Sdg199075 if (rcip->ri_gate_hp != NULL && 1048b2a92f83Sdg199075 rcip->ri_gate_hp->h_addrtype == AF_INET6) 1049a59fa508Sjl138328 freehostent(rcip->ri_gate_hp); 1050a59fa508Sjl138328 free(rcip); 1051a59fa508Sjl138328 } 1052a59fa508Sjl138328 1053a59fa508Sjl138328 void 1054a59fa508Sjl138328 save_string(char **dst, char *src) 1055a59fa508Sjl138328 { 1056a59fa508Sjl138328 free(*dst); 1057a59fa508Sjl138328 *dst = strdup(src); 1058a59fa508Sjl138328 if (*dst == NULL) { 1059a59fa508Sjl138328 quit("malloc", errno); 1060a59fa508Sjl138328 } 1061a59fa508Sjl138328 } 1062a59fa508Sjl138328 1063a59fa508Sjl138328 /* 1064a59fa508Sjl138328 * Print the short form summary of a route command. 1065a59fa508Sjl138328 * Eg. "add net default: gateway 10.0.0.1" 1066a59fa508Sjl138328 * The final newline is not added, allowing the caller to append additional 1067a59fa508Sjl138328 * information. 1068a59fa508Sjl138328 */ 1069a59fa508Sjl138328 void 1070a59fa508Sjl138328 print_rtcmd_short(FILE *to, rtcmd_irep_t *rcip, boolean_t gw_good, 1071a59fa508Sjl138328 boolean_t to_saved) 1072a59fa508Sjl138328 { 1073a59fa508Sjl138328 char *cmd; 1074a59fa508Sjl138328 char obuf[INET6_ADDRSTRLEN]; 1075a59fa508Sjl138328 1076a59fa508Sjl138328 switch (rcip->ri_cmd) { 1077a59fa508Sjl138328 case RTM_ADD: 1078a59fa508Sjl138328 cmd = "add"; 1079a59fa508Sjl138328 break; 1080a59fa508Sjl138328 case RTM_CHANGE: 1081a59fa508Sjl138328 cmd = "change"; 1082a59fa508Sjl138328 break; 1083a59fa508Sjl138328 case RTM_DELETE: 1084a59fa508Sjl138328 cmd = "delete"; 1085a59fa508Sjl138328 break; 1086a59fa508Sjl138328 case RTM_GET: 1087a59fa508Sjl138328 cmd = "get"; 1088a59fa508Sjl138328 break; 1089a59fa508Sjl138328 default: 1090a59fa508Sjl138328 assert(0); 1091a59fa508Sjl138328 } 1092a59fa508Sjl138328 1093a59fa508Sjl138328 (void) fprintf(to, "%s%s %s %s", cmd, 1094a59fa508Sjl138328 (to_saved) ? " persistent" : "", 1095a59fa508Sjl138328 (rcip->ri_flags & RTF_HOST) ? "host" : "net", 1096a59fa508Sjl138328 (rcip->ri_dest_str == NULL) ? "NULL" : rcip->ri_dest_str); 1097a59fa508Sjl138328 1098a59fa508Sjl138328 if (rcip->ri_gate_str != NULL) { 1099a59fa508Sjl138328 switch (rcip->ri_af) { 1100a59fa508Sjl138328 case AF_INET: 1101a59fa508Sjl138328 if (nflag) { 1102a59fa508Sjl138328 (void) fprintf(to, ": gateway %s", 1103a59fa508Sjl138328 inet_ntoa(rcip->ri_gate.sin.sin_addr)); 1104a59fa508Sjl138328 } else if (gw_good && 1105a59fa508Sjl138328 rcip->ri_gate_hp != NULL && 1106a59fa508Sjl138328 rcip->ri_gate_hp->h_addr_list[1] != NULL) { 1107a59fa508Sjl138328 /* 1108a59fa508Sjl138328 * Print the actual address used in the case 1109a59fa508Sjl138328 * where there was more than one address 1110a59fa508Sjl138328 * available for the name, and one was used 1111a59fa508Sjl138328 * successfully. 1112a59fa508Sjl138328 */ 1113a59fa508Sjl138328 (void) fprintf(to, ": gateway %s (%s)", 1114a59fa508Sjl138328 rcip->ri_gate_str, 1115a59fa508Sjl138328 inet_ntoa(rcip->ri_gate.sin.sin_addr)); 1116a59fa508Sjl138328 } else { 1117a59fa508Sjl138328 (void) fprintf(to, ": gateway %s", 1118a59fa508Sjl138328 rcip->ri_gate_str); 1119a59fa508Sjl138328 } 1120a59fa508Sjl138328 break; 1121a59fa508Sjl138328 case AF_INET6: 1122a59fa508Sjl138328 if (inet_ntop(AF_INET6, 1123a59fa508Sjl138328 &rcip->ri_gate.sin6.sin6_addr, obuf, 1124a59fa508Sjl138328 INET6_ADDRSTRLEN) != NULL) { 1125a59fa508Sjl138328 if (nflag) { 1126a59fa508Sjl138328 (void) fprintf(to, ": gateway %s", 1127a59fa508Sjl138328 obuf); 1128a59fa508Sjl138328 break; 1129a59fa508Sjl138328 } 1130a59fa508Sjl138328 if (gw_good && 1131a59fa508Sjl138328 rcip->ri_gate_hp->h_addr_list[1] != NULL) { 1132a59fa508Sjl138328 (void) fprintf(to, ": gateway %s (%s)", 1133a59fa508Sjl138328 rcip->ri_gate_str, obuf); 1134a59fa508Sjl138328 break; 1135a59fa508Sjl138328 } 1136a59fa508Sjl138328 } 1137a59fa508Sjl138328 /* FALLTHROUGH */ 1138a59fa508Sjl138328 default: 1139a59fa508Sjl138328 (void) fprintf(to, ": gateway %s", 1140a59fa508Sjl138328 rcip->ri_gate_str); 1141a59fa508Sjl138328 break; 1142a59fa508Sjl138328 } 1143a59fa508Sjl138328 } 1144a59fa508Sjl138328 } 1145a59fa508Sjl138328 1146a59fa508Sjl138328 void 1147a59fa508Sjl138328 set_metric(rtcmd_irep_t *rcip, char *value, int key, boolean_t lock) 11487c478bd9Sstevel@tonic-gate { 11497c478bd9Sstevel@tonic-gate int flag = 0; 11507c478bd9Sstevel@tonic-gate uint_t noval, *valp = &noval; 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate switch (key) { 1153a59fa508Sjl138328 #define caseof(x, y, z) \ 1154a59fa508Sjl138328 case (x): valp = &(rcip->ri_metrics.z); flag = (y); break 1155a59fa508Sjl138328 11567c478bd9Sstevel@tonic-gate caseof(K_MTU, RTV_MTU, rmx_mtu); 11577c478bd9Sstevel@tonic-gate caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 11587c478bd9Sstevel@tonic-gate caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 11597c478bd9Sstevel@tonic-gate caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 11607c478bd9Sstevel@tonic-gate caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 11617c478bd9Sstevel@tonic-gate caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 11627c478bd9Sstevel@tonic-gate caseof(K_RTT, RTV_RTT, rmx_rtt); 11637c478bd9Sstevel@tonic-gate caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 11647c478bd9Sstevel@tonic-gate #undef caseof 11657c478bd9Sstevel@tonic-gate } 1166a59fa508Sjl138328 rcip->ri_inits |= flag; 1167a59fa508Sjl138328 if (lock) 1168a59fa508Sjl138328 rcip->ri_metrics.rmx_locks |= flag; 11697c478bd9Sstevel@tonic-gate *valp = atoi(value); 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate 1172a59fa508Sjl138328 /* 1173a59fa508Sjl138328 * Parse the options give in argv[], filling in rcip with the results. 1174a59fa508Sjl138328 * If cmd_string is non-null, argc and argv are ignored, and cmd_string is 1175a59fa508Sjl138328 * tokenized to produce the command line. Cmd_string is tokenized using 1176a59fa508Sjl138328 * strtok, which will overwrite whitespace in the string with nulls. 1177a59fa508Sjl138328 * 1178a59fa508Sjl138328 * Returns B_TRUE on success and B_FALSE on failure. 1179a59fa508Sjl138328 */ 1180a59fa508Sjl138328 boolean_t 1181a59fa508Sjl138328 args_to_rtcmd(rtcmd_irep_t *rcip, char **argv, char *cmd_string) 11827c478bd9Sstevel@tonic-gate { 1183a59fa508Sjl138328 const char *ws = "\f\n\r\t\v "; 1184a59fa508Sjl138328 char *tok = cmd_string; 1185a59fa508Sjl138328 char *keyword_str; 1186a59fa508Sjl138328 addr_type_t atype = ADDR_TYPE_ANY; 1187a59fa508Sjl138328 boolean_t iflag = B_FALSE; 1188a59fa508Sjl138328 boolean_t locknext = B_FALSE; 1189a59fa508Sjl138328 boolean_t lockrest = B_FALSE; 1190a59fa508Sjl138328 boolean_t dash_keyword; 11917c478bd9Sstevel@tonic-gate int key; 1192a59fa508Sjl138328 char *err; 11937c478bd9Sstevel@tonic-gate 1194a59fa508Sjl138328 if (cmd_string == NULL) { 1195a59fa508Sjl138328 tok = argv[0]; 1196a59fa508Sjl138328 } else { 1197a59fa508Sjl138328 tok = strtok(cmd_string, ws); 11987c478bd9Sstevel@tonic-gate } 1199a59fa508Sjl138328 1200a59fa508Sjl138328 /* 1201a59fa508Sjl138328 * The command keywords are already fully checked by main() or 1202a59fa508Sjl138328 * search_rtfile(). 1203a59fa508Sjl138328 */ 1204a59fa508Sjl138328 switch (*tok) { 1205a59fa508Sjl138328 case 'a': 1206a59fa508Sjl138328 rcip->ri_cmd = RTM_ADD; 1207a59fa508Sjl138328 break; 1208a59fa508Sjl138328 case 'c': 1209a59fa508Sjl138328 rcip->ri_cmd = RTM_CHANGE; 1210a59fa508Sjl138328 break; 1211a59fa508Sjl138328 case 'd': 1212a59fa508Sjl138328 rcip->ri_cmd = RTM_DELETE; 1213a59fa508Sjl138328 break; 1214a59fa508Sjl138328 case 'g': 1215a59fa508Sjl138328 rcip->ri_cmd = RTM_GET; 1216a59fa508Sjl138328 break; 1217a59fa508Sjl138328 default: 1218a59fa508Sjl138328 /* NOTREACHED */ 1219a59fa508Sjl138328 quit(gettext("Internal Error"), EINVAL); 1220a59fa508Sjl138328 /* NOTREACHED */ 1221a59fa508Sjl138328 } 1222a59fa508Sjl138328 1223a59fa508Sjl138328 #define NEXTTOKEN \ 1224a59fa508Sjl138328 ((tok = (cmd_string == NULL ? *++argv : strtok(NULL, ws))) != NULL) 1225a59fa508Sjl138328 1226a59fa508Sjl138328 while (NEXTTOKEN) { 1227a59fa508Sjl138328 keyword_str = tok; 1228a59fa508Sjl138328 if (*tok == '-') { 1229a59fa508Sjl138328 dash_keyword = B_TRUE; 1230a59fa508Sjl138328 key = keyword(tok + 1); 1231a59fa508Sjl138328 } else { 1232a59fa508Sjl138328 dash_keyword = B_FALSE; 1233a59fa508Sjl138328 key = keyword(tok); 1234a59fa508Sjl138328 if (key != K_HOST && key != K_NET) { 1235a59fa508Sjl138328 /* All others must be preceded by '-' */ 1236a59fa508Sjl138328 key = 0; 1237a59fa508Sjl138328 } 1238a59fa508Sjl138328 } 1239a59fa508Sjl138328 switch (key) { 1240a59fa508Sjl138328 case K_HOST: 1241a59fa508Sjl138328 if (atype == ADDR_TYPE_NET) { 1242a59fa508Sjl138328 syntax_error(gettext("route: -host and -net " 1243a59fa508Sjl138328 "are mutually exclusive\n")); 1244a59fa508Sjl138328 return (B_FALSE); 1245a59fa508Sjl138328 } 1246a59fa508Sjl138328 atype = ADDR_TYPE_HOST; 1247a59fa508Sjl138328 break; 1248a59fa508Sjl138328 case K_NET: 1249a59fa508Sjl138328 if (atype == ADDR_TYPE_HOST) { 1250a59fa508Sjl138328 syntax_error(gettext("route: -host and -net " 1251a59fa508Sjl138328 "are mutually exclusive\n")); 1252a59fa508Sjl138328 return (B_FALSE); 1253a59fa508Sjl138328 } 1254a59fa508Sjl138328 atype = ADDR_TYPE_NET; 1255a59fa508Sjl138328 break; 12567c478bd9Sstevel@tonic-gate case K_LINK: 1257a59fa508Sjl138328 rcip->ri_af = AF_LINK; 12587c478bd9Sstevel@tonic-gate break; 12597c478bd9Sstevel@tonic-gate case K_INET: 1260a59fa508Sjl138328 rcip->ri_af = AF_INET; 12617c478bd9Sstevel@tonic-gate break; 12627c478bd9Sstevel@tonic-gate case K_SA: 1263a59fa508Sjl138328 rcip->ri_af = PF_ROUTE; 12647c478bd9Sstevel@tonic-gate break; 12657c478bd9Sstevel@tonic-gate case K_INET6: 1266a59fa508Sjl138328 rcip->ri_af = AF_INET6; 12677c478bd9Sstevel@tonic-gate break; 12687c478bd9Sstevel@tonic-gate case K_IFACE: 12697c478bd9Sstevel@tonic-gate case K_INTERFACE: 12707c478bd9Sstevel@tonic-gate iflag = B_TRUE; 1271a59fa508Sjl138328 /* fallthrough */ 12727c478bd9Sstevel@tonic-gate case K_NOSTATIC: 1273a59fa508Sjl138328 rcip->ri_flags &= ~RTF_STATIC; 12747c478bd9Sstevel@tonic-gate break; 12757c478bd9Sstevel@tonic-gate case K_LOCK: 1276a59fa508Sjl138328 locknext = B_TRUE; 12777c478bd9Sstevel@tonic-gate break; 12787c478bd9Sstevel@tonic-gate case K_LOCKREST: 12797c478bd9Sstevel@tonic-gate lockrest = B_TRUE; 12807c478bd9Sstevel@tonic-gate break; 12817c478bd9Sstevel@tonic-gate case K_REJECT: 1282a59fa508Sjl138328 rcip->ri_flags |= RTF_REJECT; 12837c478bd9Sstevel@tonic-gate break; 12847c478bd9Sstevel@tonic-gate case K_BLACKHOLE: 1285a59fa508Sjl138328 rcip->ri_flags |= RTF_BLACKHOLE; 12867c478bd9Sstevel@tonic-gate break; 12877c478bd9Sstevel@tonic-gate case K_PROTO1: 1288a59fa508Sjl138328 rcip->ri_flags |= RTF_PROTO1; 12897c478bd9Sstevel@tonic-gate break; 12907c478bd9Sstevel@tonic-gate case K_PROTO2: 1291a59fa508Sjl138328 rcip->ri_flags |= RTF_PROTO2; 12927c478bd9Sstevel@tonic-gate break; 12937c478bd9Sstevel@tonic-gate case K_CLONING: 1294a59fa508Sjl138328 rcip->ri_flags |= RTF_CLONING; 12957c478bd9Sstevel@tonic-gate break; 12967c478bd9Sstevel@tonic-gate case K_XRESOLVE: 1297a59fa508Sjl138328 rcip->ri_flags |= RTF_XRESOLVE; 12987c478bd9Sstevel@tonic-gate break; 12997c478bd9Sstevel@tonic-gate case K_STATIC: 1300a59fa508Sjl138328 rcip->ri_flags |= RTF_STATIC; 13017c478bd9Sstevel@tonic-gate break; 13027c478bd9Sstevel@tonic-gate case K_IFA: 1303a59fa508Sjl138328 if (!NEXTTOKEN) { 1304a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1305a59fa508Sjl138328 return (B_FALSE); 1306a59fa508Sjl138328 } 1307a59fa508Sjl138328 if (!getaddr(rcip, RTA_IFA, tok, atype)) { 1308a59fa508Sjl138328 return (B_FALSE); 1309a59fa508Sjl138328 } 13107c478bd9Sstevel@tonic-gate break; 13117c478bd9Sstevel@tonic-gate case K_IFP: 1312a59fa508Sjl138328 if (!NEXTTOKEN) { 1313a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1314a59fa508Sjl138328 return (B_FALSE); 1315a59fa508Sjl138328 } 1316a59fa508Sjl138328 if (!getaddr(rcip, RTA_IFP, tok, atype)) { 1317a59fa508Sjl138328 return (B_FALSE); 1318a59fa508Sjl138328 } 13197c478bd9Sstevel@tonic-gate break; 13207c478bd9Sstevel@tonic-gate case K_GATEWAY: 1321a59fa508Sjl138328 if (!NEXTTOKEN) { 1322a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1323a59fa508Sjl138328 return (B_FALSE); 1324a59fa508Sjl138328 } 1325a59fa508Sjl138328 if (!getaddr(rcip, RTA_GATEWAY, tok, atype)) { 1326a59fa508Sjl138328 return (B_FALSE); 1327a59fa508Sjl138328 } 13287c478bd9Sstevel@tonic-gate break; 13297c478bd9Sstevel@tonic-gate case K_DST: 1330a59fa508Sjl138328 if (!NEXTTOKEN) { 1331a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1332a59fa508Sjl138328 return (B_FALSE); 1333a59fa508Sjl138328 } 1334a59fa508Sjl138328 if (!getaddr(rcip, RTA_DST, tok, atype)) { 1335a59fa508Sjl138328 return (B_FALSE); 1336a59fa508Sjl138328 } 13377c478bd9Sstevel@tonic-gate break; 13387c478bd9Sstevel@tonic-gate case K_NETMASK: 1339a59fa508Sjl138328 if (!NEXTTOKEN) { 1340a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1341a59fa508Sjl138328 return (B_FALSE); 1342a59fa508Sjl138328 } 1343a59fa508Sjl138328 if (!getaddr(rcip, RTA_NETMASK, tok, atype)) { 1344a59fa508Sjl138328 return (B_FALSE); 1345a59fa508Sjl138328 } 1346a59fa508Sjl138328 atype = ADDR_TYPE_NET; 13477c478bd9Sstevel@tonic-gate break; 13487c478bd9Sstevel@tonic-gate case K_MTU: 13497c478bd9Sstevel@tonic-gate case K_HOPCOUNT: 13507c478bd9Sstevel@tonic-gate case K_EXPIRE: 13517c478bd9Sstevel@tonic-gate case K_RECVPIPE: 13527c478bd9Sstevel@tonic-gate case K_SENDPIPE: 13537c478bd9Sstevel@tonic-gate case K_SSTHRESH: 13547c478bd9Sstevel@tonic-gate case K_RTT: 13557c478bd9Sstevel@tonic-gate case K_RTTVAR: 1356a59fa508Sjl138328 if (!NEXTTOKEN) { 1357a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1358a59fa508Sjl138328 return (B_FALSE); 1359a59fa508Sjl138328 } 1360a59fa508Sjl138328 set_metric(rcip, tok, key, locknext || lockrest); 1361a59fa508Sjl138328 locknext = B_FALSE; 13627c478bd9Sstevel@tonic-gate break; 13637c478bd9Sstevel@tonic-gate case K_PRIVATE: 1364a59fa508Sjl138328 rcip->ri_flags |= RTF_PRIVATE; 13657c478bd9Sstevel@tonic-gate break; 13667c478bd9Sstevel@tonic-gate case K_MULTIRT: 1367a59fa508Sjl138328 rcip->ri_flags |= RTF_MULTIRT; 13687c478bd9Sstevel@tonic-gate break; 13697c478bd9Sstevel@tonic-gate case K_SETSRC: 1370a59fa508Sjl138328 if (!NEXTTOKEN) { 1371a59fa508Sjl138328 syntax_arg_missing(keyword_str); 1372a59fa508Sjl138328 return (B_FALSE); 1373a59fa508Sjl138328 } 1374a59fa508Sjl138328 if (!getaddr(rcip, RTA_SRC, tok, atype)) { 1375a59fa508Sjl138328 return (B_FALSE); 1376a59fa508Sjl138328 } 1377a59fa508Sjl138328 rcip->ri_flags |= RTF_SETSRC; 13787c478bd9Sstevel@tonic-gate break; 137945916cd2Sjpk case K_SECATTR: 138045916cd2Sjpk if (!NEXTTOKEN) { 138145916cd2Sjpk syntax_arg_missing(keyword_str); 138245916cd2Sjpk return (B_FALSE); 138345916cd2Sjpk } 1384e34b0294Swy83408 if (is_system_labeled()) { 138545916cd2Sjpk int err; 138645916cd2Sjpk 1387e34b0294Swy83408 if (rcip->ri_rtsa_cnt >= 1) { 1388e34b0294Swy83408 syntax_error(gettext("route: can't " 1389e34b0294Swy83408 "specify more than one security " 1390e34b0294Swy83408 "attribute\n")); 1391e34b0294Swy83408 return (B_FALSE); 1392e34b0294Swy83408 } 139345916cd2Sjpk if (!rtsa_keyword(tok, &rcip->ri_rtsa, &err, 139445916cd2Sjpk NULL)) { 1395e34b0294Swy83408 syntax_error(gettext("route: " 139645916cd2Sjpk "bad security attribute: %s\n"), 139745916cd2Sjpk tsol_strerror(err, errno)); 139845916cd2Sjpk return (B_FALSE); 139945916cd2Sjpk } 1400e34b0294Swy83408 rcip->ri_rtsa_cnt++; 1401e34b0294Swy83408 } else { 1402e34b0294Swy83408 syntax_error(gettext("route: " 1403e34b0294Swy83408 "system is not labeled; cannot specify " 1404e34b0294Swy83408 "security attributes.\n")); 140545916cd2Sjpk return (B_FALSE); 140645916cd2Sjpk } 140745916cd2Sjpk break; 1408*bd670b35SErik Nordmark case K_INDIRECT: 1409*bd670b35SErik Nordmark rcip->ri_flags |= RTF_INDIRECT; 1410*bd670b35SErik Nordmark break; 14117c478bd9Sstevel@tonic-gate default: 1412a59fa508Sjl138328 if (dash_keyword) { 1413a59fa508Sjl138328 syntax_bad_keyword(tok + 1); 1414a59fa508Sjl138328 return (B_FALSE); 14157c478bd9Sstevel@tonic-gate } 1416a59fa508Sjl138328 if ((rcip->ri_addrs & RTA_DST) == 0) { 1417a59fa508Sjl138328 if (!getaddr(rcip, RTA_DST, tok, atype)) { 1418a59fa508Sjl138328 return (B_FALSE); 1419a59fa508Sjl138328 } 1420a59fa508Sjl138328 } else if ((rcip->ri_addrs & RTA_GATEWAY) == 0) { 14217c478bd9Sstevel@tonic-gate /* 14227c478bd9Sstevel@tonic-gate * For the gateway parameter, retrieve the 14237c478bd9Sstevel@tonic-gate * pointer to the struct hostent so that all 14247c478bd9Sstevel@tonic-gate * possible addresses can be tried until one 14257c478bd9Sstevel@tonic-gate * is successful. 14267c478bd9Sstevel@tonic-gate */ 1427a59fa508Sjl138328 if (!getaddr(rcip, RTA_GATEWAY, tok, atype)) { 1428a59fa508Sjl138328 return (B_FALSE); 1429a59fa508Sjl138328 } 14307c478bd9Sstevel@tonic-gate } else { 1431a59fa508Sjl138328 ulong_t metric; 14327c478bd9Sstevel@tonic-gate /* 14337c478bd9Sstevel@tonic-gate * Assume that a regular number is a metric. 14347c478bd9Sstevel@tonic-gate * Needed for compatibility with old route 14357c478bd9Sstevel@tonic-gate * command syntax. 14367c478bd9Sstevel@tonic-gate */ 1437a59fa508Sjl138328 errno = 0; 1438a59fa508Sjl138328 metric = strtoul(tok, &err, 10); 1439a59fa508Sjl138328 if (errno == 0 && *err == '\0' && 14407c478bd9Sstevel@tonic-gate metric < 0x80000000ul) { 14417c478bd9Sstevel@tonic-gate iflag = (metric == 0); 14427c478bd9Sstevel@tonic-gate if (verbose) { 14437c478bd9Sstevel@tonic-gate (void) printf("old usage of " 14447c478bd9Sstevel@tonic-gate "trailing number, assuming " 14457c478bd9Sstevel@tonic-gate "route %s\n", iflag ? 14467c478bd9Sstevel@tonic-gate "to if" : "via gateway"); 14477c478bd9Sstevel@tonic-gate } 14487c478bd9Sstevel@tonic-gate continue; 14497c478bd9Sstevel@tonic-gate } 1450a59fa508Sjl138328 if (!getaddr(rcip, RTA_NETMASK, tok, atype)) { 1451a59fa508Sjl138328 return (B_FALSE); 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate } 1455a59fa508Sjl138328 } 1456a59fa508Sjl138328 #undef NEXTTOKEN 1457a59fa508Sjl138328 1458a59fa508Sjl138328 if ((rcip->ri_addrs & RTA_DST) == 0) { 1459a59fa508Sjl138328 syntax_error(gettext("route: destination required\n")); 1460a59fa508Sjl138328 return (B_FALSE); 1461a59fa508Sjl138328 } else if ((rcip->ri_cmd == RTM_ADD || rcip->ri_cmd == RTM_DELETE) && 1462a59fa508Sjl138328 (rcip->ri_addrs & RTA_GATEWAY) == 0) { 1463a59fa508Sjl138328 syntax_error(gettext( 1464a59fa508Sjl138328 "route: gateway required for add or delete command\n")); 1465a59fa508Sjl138328 return (B_FALSE); 1466a59fa508Sjl138328 } 1467a59fa508Sjl138328 1468a59fa508Sjl138328 if (!iflag) { 1469a59fa508Sjl138328 rcip->ri_flags |= RTF_GATEWAY; 1470a59fa508Sjl138328 } 1471a59fa508Sjl138328 1472a59fa508Sjl138328 if (atype != ADDR_TYPE_NET) { 1473a59fa508Sjl138328 if (rcip->ri_addrs & RTA_NETMASK) { 1474a59fa508Sjl138328 /* 1475a59fa508Sjl138328 * We know the netmask, so we can set the host flag 1476a59fa508Sjl138328 * based on whether the netmask is the host netmask. 1477a59fa508Sjl138328 */ 1478a59fa508Sjl138328 if (rcip->ri_af == AF_INET && 1479a59fa508Sjl138328 rcip->ri_mask.sin.sin_addr.s_addr == 1480a59fa508Sjl138328 IP_HOST_MASK) { 1481a59fa508Sjl138328 rcip->ri_flags |= RTF_HOST; 1482a59fa508Sjl138328 } 1483a59fa508Sjl138328 if (rcip->ri_af == AF_INET6 && 1484a59fa508Sjl138328 memcmp(&rcip->ri_mask.sin6.sin6_addr, 1485a59fa508Sjl138328 &in6_host_mask, 1486a59fa508Sjl138328 sizeof (struct in6_addr)) == 0) { 1487a59fa508Sjl138328 rcip->ri_flags |= RTF_HOST; 1488a59fa508Sjl138328 } 1489a59fa508Sjl138328 } else { 1490a59fa508Sjl138328 /* 1491a59fa508Sjl138328 * If no prefix mask has been saved at this point, it 1492a59fa508Sjl138328 * only makes sense to treat the destination address 1493a59fa508Sjl138328 * as a host address. 1494a59fa508Sjl138328 */ 1495a59fa508Sjl138328 rcip->ri_flags |= RTF_HOST; 1496a59fa508Sjl138328 } 1497a59fa508Sjl138328 } 1498a59fa508Sjl138328 return (B_TRUE); 14993f33f4f7Sjl138328 } 15007a23074eSdduvall 15017a23074eSdduvall /* 1502a59fa508Sjl138328 * This command always seeks to the end of the file prior to writing. 15037a23074eSdduvall */ 1504a59fa508Sjl138328 void 1505a59fa508Sjl138328 write_to_rtfile(FILE *fp, int argc, char **argv) 1506a59fa508Sjl138328 { 1507a59fa508Sjl138328 char file_line[BUF_SIZE]; 1508a59fa508Sjl138328 int len; 1509a59fa508Sjl138328 int i; 1510a59fa508Sjl138328 1511a59fa508Sjl138328 len = 0; 1512a59fa508Sjl138328 if (early_v6_keyword) { 1513a59fa508Sjl138328 /* 1514a59fa508Sjl138328 * This flag is set when "inet6" was seen as an 1515a59fa508Sjl138328 * argument to the -f flag. Normally, when writing 1516a59fa508Sjl138328 * routes to the persistent route file, everything on 1517a59fa508Sjl138328 * the command line after "add" is saved verbatim. 1518a59fa508Sjl138328 * In this case, the arguments after "add" may not be 1519a59fa508Sjl138328 * sufficient, as the ipv6 keyword came before "add", 1520a59fa508Sjl138328 * yet must be present in the persistent route file. 1521a59fa508Sjl138328 */ 1522a59fa508Sjl138328 len += snprintf(file_line, BUF_SIZE, "-inet6 "); 15233f33f4f7Sjl138328 } 1524a59fa508Sjl138328 for (i = 0; argc > 0 && len < BUF_SIZE; i++, argc--) { 1525a59fa508Sjl138328 len += snprintf(&file_line[len], BUF_SIZE - len, "%s ", 1526a59fa508Sjl138328 argv[i]); 1527a59fa508Sjl138328 } 1528a59fa508Sjl138328 if (len >= BUF_SIZE) 1529a59fa508Sjl138328 quit(gettext("Internal Error"), EINVAL); 1530a59fa508Sjl138328 file_line[len - 1] = '\n'; 1531a59fa508Sjl138328 if (fseek(fp, 0, SEEK_END) != 0 || 1532a59fa508Sjl138328 fputs(file_line, fp) == EOF) { 1533a59fa508Sjl138328 quit(gettext("failed to write to route file"), 1534a59fa508Sjl138328 errno); 1535a59fa508Sjl138328 } 1536a59fa508Sjl138328 } 1537a59fa508Sjl138328 1538a59fa508Sjl138328 boolean_t 1539a59fa508Sjl138328 compare_rtcmd(rtcmd_irep_t *srch_rt, rtcmd_irep_t *file_rt) 1540a59fa508Sjl138328 { 1541a59fa508Sjl138328 if (strcmp(srch_rt->ri_dest_str, file_rt->ri_dest_str) != 0 || 1542a59fa508Sjl138328 memcmp(&srch_rt->ri_mask, &file_rt->ri_mask, sizeof (su_t)) != 0) { 1543a59fa508Sjl138328 return (B_FALSE); 1544a59fa508Sjl138328 } 1545a59fa508Sjl138328 return (srch_rt->ri_gate_str == NULL || 1546a59fa508Sjl138328 strcmp(srch_rt->ri_gate_str, file_rt->ri_gate_str) == 0); 1547a59fa508Sjl138328 } 1548a59fa508Sjl138328 1549a59fa508Sjl138328 /* 1550a59fa508Sjl138328 * Search the route file for routes matching the supplied route. There are 3 1551a59fa508Sjl138328 * modes of operation: 1552a59fa508Sjl138328 * SEARCH_MODE_RET - no side effects. 1553a59fa508Sjl138328 * SEARCH_MODE_PRINT - prints each matching line. 1554a59fa508Sjl138328 * SEARCH_MODE_DEL - copies all valid, non-matching lines to tmp_fp. 1555a59fa508Sjl138328 * 1556a59fa508Sjl138328 * In all cases, the number of matches is returned. If rt is NULL, all routes 1557a59fa508Sjl138328 * matching the global af value are considered matching. 1558a59fa508Sjl138328 */ 1559a59fa508Sjl138328 int 1560a59fa508Sjl138328 search_rtfile(FILE *fp, FILE *temp_fp, rtcmd_irep_t *rt, search_mode_t mode) 1561a59fa508Sjl138328 { 1562a59fa508Sjl138328 char *tmp_buf; 1563a59fa508Sjl138328 int match_cnt; 1564a59fa508Sjl138328 boolean_t match; 1565a59fa508Sjl138328 char file_line[BUF_SIZE + 4] = "add "; 1566a59fa508Sjl138328 rtcmd_irep_t *thisrt; 1567a59fa508Sjl138328 1568a59fa508Sjl138328 match_cnt = 0; 1569a59fa508Sjl138328 1570a59fa508Sjl138328 /* 1571a59fa508Sjl138328 * Leave space at the beginning of file_line for "add ". 1572a59fa508Sjl138328 */ 1573a59fa508Sjl138328 while (fgets(file_line + 4, BUF_SIZE, fp) != NULL) { 1574a59fa508Sjl138328 1575a59fa508Sjl138328 if (file_line[4] == '#' || file_line[4] == '\n') { 1576a59fa508Sjl138328 /* Handle comments and blank lines */ 1577a59fa508Sjl138328 if (mode == SEARCH_MODE_DEL && 1578a59fa508Sjl138328 fputs(file_line + 4, temp_fp) == EOF) { 1579a59fa508Sjl138328 quit(gettext( 1580a59fa508Sjl138328 "route: failed to write to temp file"), 1581a59fa508Sjl138328 errno); 1582a59fa508Sjl138328 } 1583a59fa508Sjl138328 continue; 1584a59fa508Sjl138328 } 1585a59fa508Sjl138328 thisrt = new_rtcmd_irep(); 1586a59fa508Sjl138328 /* 1587a59fa508Sjl138328 * thisrt->ri_af defaults to whatever address family happens 1588a59fa508Sjl138328 * to be set in the global af, but routes in the persistent 1589a59fa508Sjl138328 * route file must be treated as AF_INET by default. 1590a59fa508Sjl138328 */ 1591a59fa508Sjl138328 thisrt->ri_af = AF_INET; 1592a59fa508Sjl138328 1593a59fa508Sjl138328 exit_on_error = B_FALSE; 1594a59fa508Sjl138328 tmp_buf = strdup(file_line); 1595a59fa508Sjl138328 /* args_to_rtcmd() will mangle the string passed. */ 1596a59fa508Sjl138328 if (!args_to_rtcmd(thisrt, NULL, tmp_buf)) { 1597a59fa508Sjl138328 /* There was an error in args_to_rtcmd() or helpers */ 1598a59fa508Sjl138328 del_rtcmd_irep(thisrt); 1599a59fa508Sjl138328 free(tmp_buf); 1600a59fa508Sjl138328 continue; 1601a59fa508Sjl138328 } 1602a59fa508Sjl138328 exit_on_error = B_TRUE; 1603a59fa508Sjl138328 free(tmp_buf); 1604a59fa508Sjl138328 1605a59fa508Sjl138328 if (thisrt->ri_gate_str == NULL) { 1606a59fa508Sjl138328 del_rtcmd_irep(thisrt); 1607a59fa508Sjl138328 continue; 1608a59fa508Sjl138328 } 1609a59fa508Sjl138328 match = (rt == NULL) ? (thisrt->ri_af == af) : 1610a59fa508Sjl138328 compare_rtcmd(rt, thisrt); 1611a59fa508Sjl138328 1612a59fa508Sjl138328 if (match) match_cnt++; 1613a59fa508Sjl138328 if (match && mode == SEARCH_MODE_PRINT) { 1614a59fa508Sjl138328 (void) printf("persistent: route %s", file_line); 1615a59fa508Sjl138328 } 1616a59fa508Sjl138328 if (match && mode == SEARCH_MODE_DEL) { 1617a59fa508Sjl138328 thisrt->ri_cmd = RTM_DELETE; 1618a59fa508Sjl138328 print_rtcmd_short(stdout, thisrt, B_FALSE, B_TRUE); 1619a59fa508Sjl138328 (void) printf("\n"); 1620a59fa508Sjl138328 } 1621a59fa508Sjl138328 del_rtcmd_irep(thisrt); 1622a59fa508Sjl138328 1623a59fa508Sjl138328 if (!match && mode == SEARCH_MODE_DEL && 1624a59fa508Sjl138328 fputs(file_line + 4, temp_fp) == EOF) { 1625a59fa508Sjl138328 quit(gettext("failed to write to temp file"), 1626a59fa508Sjl138328 errno); 1627a59fa508Sjl138328 } 1628a59fa508Sjl138328 } 1629a59fa508Sjl138328 return (match_cnt); 1630a59fa508Sjl138328 } 1631a59fa508Sjl138328 1632a59fa508Sjl138328 /* 1633a59fa508Sjl138328 * Perform the route operation given in argv on the persistent route file. 1634a59fa508Sjl138328 * If do_flush is set, the persistent route file is flushed of all routes 1635a59fa508Sjl138328 * matching the global family, and the arguments are ignored. 1636a59fa508Sjl138328 */ 1637a59fa508Sjl138328 void 1638a59fa508Sjl138328 save_route(int argc, char **argv, int do_flush) 1639a59fa508Sjl138328 { 1640a59fa508Sjl138328 rtcmd_irep_t *rt; 1641a59fa508Sjl138328 int perm_fd; 1642a59fa508Sjl138328 FILE *perm_fp; 1643a59fa508Sjl138328 FILE *temp_fp; 1644a59fa508Sjl138328 mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 1645a59fa508Sjl138328 struct flock lock; 1646a59fa508Sjl138328 struct stat st; 1647a59fa508Sjl138328 const char commentstr[] = 1648a59fa508Sjl138328 "# File generated by route(1M) - do not edit.\n"; 1649a59fa508Sjl138328 1650a59fa508Sjl138328 perm_fd = open(perm_file, O_RDWR | O_CREAT, fmode); 1651a59fa508Sjl138328 if (perm_fd == -1 || fstat(perm_fd, &st) == -1) 1652a59fa508Sjl138328 quit("failed to open route file", errno); 1653a59fa508Sjl138328 1654a59fa508Sjl138328 lock.l_type = F_WRLCK; 1655a59fa508Sjl138328 lock.l_whence = SEEK_SET; 1656a59fa508Sjl138328 lock.l_start = 0; 1657a59fa508Sjl138328 lock.l_len = 0; 1658a59fa508Sjl138328 if (fcntl(perm_fd, F_SETLK, &lock) != 0) { 1659a59fa508Sjl138328 quit(gettext("failed to lock route file"), errno); 1660a59fa508Sjl138328 /* NOTREACHED */ 1661a59fa508Sjl138328 } 1662a59fa508Sjl138328 if (st.st_size == 0 && 1663a59fa508Sjl138328 write(perm_fd, commentstr, sizeof (commentstr) - 1) != 1664a59fa508Sjl138328 sizeof (commentstr) - 1) 1665a59fa508Sjl138328 quit(gettext("failed to open route file"), errno); 1666a59fa508Sjl138328 1667a59fa508Sjl138328 if ((perm_fp = fdopen(perm_fd, "r+")) == NULL) { 1668a59fa508Sjl138328 quit(gettext("failed to open route file"), errno); 1669a59fa508Sjl138328 /* NOTREACHED */ 1670a59fa508Sjl138328 } 1671a59fa508Sjl138328 1672a59fa508Sjl138328 if (!do_flush) { 1673a59fa508Sjl138328 rt = new_rtcmd_irep(); 1674a59fa508Sjl138328 (void) args_to_rtcmd(rt, argv, NULL); 1675a59fa508Sjl138328 } 1676a59fa508Sjl138328 if (do_flush || rt->ri_cmd == RTM_DELETE) { 1677a59fa508Sjl138328 if ((temp_fp = fopen(temp_file, "w")) == NULL) { 1678a59fa508Sjl138328 quit(gettext("failed to open temp file"), errno); 1679a59fa508Sjl138328 /* NOTREACHED */ 1680a59fa508Sjl138328 } 1681a59fa508Sjl138328 } 1682a59fa508Sjl138328 if (do_flush) { 1683a59fa508Sjl138328 (void) search_rtfile(perm_fp, temp_fp, NULL, SEARCH_MODE_DEL); 1684a59fa508Sjl138328 if (fclose(temp_fp) != 0 || rename(temp_file, perm_file) != 0) { 1685a59fa508Sjl138328 quit(gettext("failed to update route file"), errno); 1686a59fa508Sjl138328 /* NOTREACHED */ 1687a59fa508Sjl138328 } 1688a59fa508Sjl138328 (void) fclose(perm_fp); 1689a59fa508Sjl138328 return; 1690a59fa508Sjl138328 } 1691a59fa508Sjl138328 1692a59fa508Sjl138328 switch (rt->ri_cmd) { 1693a59fa508Sjl138328 case RTM_ADD: 1694a59fa508Sjl138328 if (search_rtfile(perm_fp, NULL, rt, SEARCH_MODE_NULL) > 0) { 1695a59fa508Sjl138328 /* Route is already in the file */ 1696a59fa508Sjl138328 print_rtcmd_short(stderr, rt, B_FALSE, B_TRUE); 1697a59fa508Sjl138328 (void) fprintf(stderr, ": entry exists\n"); 1698a59fa508Sjl138328 exit(1); 1699a59fa508Sjl138328 } 1700a59fa508Sjl138328 write_to_rtfile(perm_fp, argc - 1, argv + 1); 1701a59fa508Sjl138328 print_rtcmd_short(stdout, rt, B_FALSE, B_TRUE); 1702a59fa508Sjl138328 (void) printf("\n"); 1703a59fa508Sjl138328 break; 1704a59fa508Sjl138328 1705a59fa508Sjl138328 case RTM_CHANGE: 1706a59fa508Sjl138328 syntax_error( 1707a59fa508Sjl138328 gettext("route: change command not supported with -p\n")); 1708a59fa508Sjl138328 /* NOTREACHED */ 1709a59fa508Sjl138328 1710a59fa508Sjl138328 case RTM_DELETE: 1711a59fa508Sjl138328 if (search_rtfile(perm_fp, temp_fp, rt, SEARCH_MODE_DEL) <= 0) { 1712a59fa508Sjl138328 /* Route not found */ 1713a59fa508Sjl138328 print_rtcmd_short(stderr, rt, B_FALSE, B_TRUE); 1714a59fa508Sjl138328 (void) fprintf(stderr, gettext(": not in file\n")); 1715a59fa508Sjl138328 exit(1); 1716a59fa508Sjl138328 } 1717a59fa508Sjl138328 if (fclose(temp_fp) != 0 || rename(temp_file, perm_file) != 0) { 1718a59fa508Sjl138328 quit(gettext("failed to update route file"), errno); 1719a59fa508Sjl138328 /* NOTREACHED */ 1720a59fa508Sjl138328 } 1721a59fa508Sjl138328 break; 1722a59fa508Sjl138328 1723a59fa508Sjl138328 case RTM_GET: 1724a59fa508Sjl138328 if (search_rtfile(perm_fp, temp_fp, rt, SEARCH_MODE_PRINT) <= 1725a59fa508Sjl138328 0) { 1726a59fa508Sjl138328 print_rtcmd_short(stdout, rt, B_FALSE, B_TRUE); 1727a59fa508Sjl138328 (void) printf(gettext(": not in file\n")); 1728a59fa508Sjl138328 } 1729a59fa508Sjl138328 break; 1730a59fa508Sjl138328 1731a59fa508Sjl138328 default: 1732a59fa508Sjl138328 quit(gettext("Internal Error"), EINVAL); 1733a59fa508Sjl138328 /* NOTREACHED */ 1734a59fa508Sjl138328 } 1735a59fa508Sjl138328 1736a59fa508Sjl138328 /* 1737a59fa508Sjl138328 * Closing the file unlocks it. 1738a59fa508Sjl138328 */ 1739a59fa508Sjl138328 (void) fclose(perm_fp); 1740a59fa508Sjl138328 } 1741a59fa508Sjl138328 1742a59fa508Sjl138328 int 1743a59fa508Sjl138328 show_saved_routes(int argc) 1744a59fa508Sjl138328 { 1745a59fa508Sjl138328 int perm_fd; 1746a59fa508Sjl138328 FILE *perm_fp; 1747a59fa508Sjl138328 struct flock lock; 1748a59fa508Sjl138328 int count = 0; 1749a59fa508Sjl138328 1750a59fa508Sjl138328 if (argc != 1) { 1751a59fa508Sjl138328 syntax_error(gettext("route: invalid arguments for show\n")); 1752a59fa508Sjl138328 } 1753a59fa508Sjl138328 1754a59fa508Sjl138328 perm_fd = open(perm_file, O_RDONLY, 0); 1755a59fa508Sjl138328 1756a59fa508Sjl138328 if (perm_fd == -1) { 1757a59fa508Sjl138328 if (errno == ENOENT) { 1758a59fa508Sjl138328 (void) printf("No persistent routes are defined\n"); 1759a59fa508Sjl138328 return (0); 1760a59fa508Sjl138328 } else { 1761a59fa508Sjl138328 quit(gettext("failed to open route file"), errno); 1762a59fa508Sjl138328 } 1763a59fa508Sjl138328 } 1764a59fa508Sjl138328 lock.l_type = F_RDLCK; 1765a59fa508Sjl138328 lock.l_whence = SEEK_SET; 1766a59fa508Sjl138328 lock.l_start = 0; 1767a59fa508Sjl138328 lock.l_len = 0; 1768a59fa508Sjl138328 if (fcntl(perm_fd, F_SETLK, &lock) != 0) { 1769a59fa508Sjl138328 quit(gettext("failed to lock route file"), 1770a59fa508Sjl138328 errno); 1771a59fa508Sjl138328 /* NOTREACHED */ 1772a59fa508Sjl138328 } 1773a59fa508Sjl138328 if ((perm_fp = fdopen(perm_fd, "r")) == NULL) { 1774a59fa508Sjl138328 quit(gettext("failed to open route file"), errno); 1775a59fa508Sjl138328 /* NOTREACHED */ 1776a59fa508Sjl138328 } 1777a59fa508Sjl138328 count += search_rtfile(perm_fp, NULL, NULL, SEARCH_MODE_PRINT); 1778a59fa508Sjl138328 (void) fseek(perm_fp, 0, SEEK_SET); 1779a59fa508Sjl138328 af = AF_INET6; 1780a59fa508Sjl138328 count += search_rtfile(perm_fp, NULL, NULL, SEARCH_MODE_PRINT); 1781a59fa508Sjl138328 1782a59fa508Sjl138328 if (count == 0) 1783a59fa508Sjl138328 (void) printf("No persistent routes are defined\n"); 1784a59fa508Sjl138328 1785a59fa508Sjl138328 (void) fclose(perm_fp); 1786a59fa508Sjl138328 return (0); 1787a59fa508Sjl138328 } 1788a59fa508Sjl138328 1789a59fa508Sjl138328 int 1790a59fa508Sjl138328 newroute(char **argv) 1791a59fa508Sjl138328 { 1792a59fa508Sjl138328 rtcmd_irep_t *newrt; 1793a59fa508Sjl138328 int ret, attempts, oerrno; 1794a59fa508Sjl138328 char *err; 1795a59fa508Sjl138328 char obuf[INET6_ADDRSTRLEN]; 1796a59fa508Sjl138328 #define hp (newrt->ri_gate_hp) 1797a59fa508Sjl138328 1798a59fa508Sjl138328 newrt = new_rtcmd_irep(); 1799a59fa508Sjl138328 (void) args_to_rtcmd(newrt, argv, NULL); 1800a59fa508Sjl138328 1801a59fa508Sjl138328 if (newrt->ri_cmd != RTM_GET && !tflag) { 1802a59fa508Sjl138328 /* Don't want to read back our messages */ 1803a59fa508Sjl138328 (void) shutdown(s, 0); 1804a59fa508Sjl138328 } 1805a59fa508Sjl138328 if (newrt->ri_addrs & RTA_IFP) { 1806a59fa508Sjl138328 newrt->ri_ifp.sdl.sdl_index = if_nametoindex(newrt->ri_ifp_str); 1807a59fa508Sjl138328 if (newrt->ri_ifp.sdl.sdl_index == 0) { 1808a59fa508Sjl138328 if (errno != ENXIO) { 1809a59fa508Sjl138328 quit("if_nametoindex", errno); 1810a59fa508Sjl138328 } else { 1811a59fa508Sjl138328 (void) fprintf(stderr, 1812a59fa508Sjl138328 gettext("route: %s: no such interface\n"), 1813a59fa508Sjl138328 newrt->ri_ifp_str); 1814a59fa508Sjl138328 exit(1); 1815a59fa508Sjl138328 } 1816a59fa508Sjl138328 } 1817a59fa508Sjl138328 newrt->ri_ifp.sdl.sdl_family = AF_LINK; 1818a59fa508Sjl138328 } 18197c478bd9Sstevel@tonic-gate for (attempts = 1; ; attempts++) { 18207c478bd9Sstevel@tonic-gate errno = 0; 1821a59fa508Sjl138328 if ((ret = rtmsg(newrt)) == 0) 18227c478bd9Sstevel@tonic-gate break; 18237c478bd9Sstevel@tonic-gate if (errno != ENETUNREACH && errno != ESRCH) 18247c478bd9Sstevel@tonic-gate break; 1825a59fa508Sjl138328 if ((newrt->ri_addrs & RTA_GATEWAY) && hp != NULL && 18267c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts] != NULL) { 18277c478bd9Sstevel@tonic-gate switch (af) { 18287c478bd9Sstevel@tonic-gate case AF_INET: 1829a59fa508Sjl138328 (void) memmove(&newrt->ri_gate.sin.sin_addr, 18307c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts], hp->h_length); 18317c478bd9Sstevel@tonic-gate continue; 18327c478bd9Sstevel@tonic-gate case AF_INET6: 1833a59fa508Sjl138328 (void) memmove(&newrt->ri_gate.sin6.sin6_addr, 18347c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts], hp->h_length); 18357c478bd9Sstevel@tonic-gate continue; 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate } 18387c478bd9Sstevel@tonic-gate break; 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate oerrno = errno; 1841a59fa508Sjl138328 1842a59fa508Sjl138328 if (newrt->ri_cmd != RTM_GET) { 1843a59fa508Sjl138328 print_rtcmd_short(stdout, newrt, (ret == 0), B_FALSE); 18447a23074eSdduvall if (ret == 0) 18457a23074eSdduvall (void) printf("\n"); 1846a59fa508Sjl138328 } else if (ret != 0) { 1847a59fa508Sjl138328 /* 1848a59fa508Sjl138328 * Note: there is nothing additional to print for get 1849a59fa508Sjl138328 * if ret == 0. 1850a59fa508Sjl138328 */ 18517a23074eSdduvall if (nflag) { 1852a59fa508Sjl138328 switch (newrt->ri_af) { 18537a23074eSdduvall case AF_INET: 18547a23074eSdduvall (void) printf(" %s", 1855a59fa508Sjl138328 inet_ntoa(newrt->ri_dst.sin.sin_addr)); 18567a23074eSdduvall break; 18577a23074eSdduvall case AF_INET6: 18587a23074eSdduvall if (inet_ntop(AF_INET6, 1859a59fa508Sjl138328 (void *)&newrt->ri_dst.sin6.sin6_addr, 18607c478bd9Sstevel@tonic-gate obuf, INET6_ADDRSTRLEN) != NULL) { 18617c478bd9Sstevel@tonic-gate (void) printf(" %s", obuf); 18627c478bd9Sstevel@tonic-gate break; 18637c478bd9Sstevel@tonic-gate } 18647c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 18657c478bd9Sstevel@tonic-gate default: 1866a59fa508Sjl138328 (void) printf("%s", newrt->ri_dest_str); 18677c478bd9Sstevel@tonic-gate break; 18687c478bd9Sstevel@tonic-gate } 18697c478bd9Sstevel@tonic-gate } else { 1870a59fa508Sjl138328 (void) printf("%s", newrt->ri_dest_str); 18717c478bd9Sstevel@tonic-gate } 18727c478bd9Sstevel@tonic-gate } 1873a59fa508Sjl138328 1874a59fa508Sjl138328 if (ret != 0) { 18757c478bd9Sstevel@tonic-gate switch (oerrno) { 18767c478bd9Sstevel@tonic-gate case ESRCH: 18777c478bd9Sstevel@tonic-gate err = "not in table"; 18787c478bd9Sstevel@tonic-gate break; 18797c478bd9Sstevel@tonic-gate case EBUSY: 18807c478bd9Sstevel@tonic-gate err = "entry in use"; 18817c478bd9Sstevel@tonic-gate break; 18827c478bd9Sstevel@tonic-gate case ENOBUFS: 18837c478bd9Sstevel@tonic-gate err = "routing table overflow"; 18847c478bd9Sstevel@tonic-gate break; 18857c478bd9Sstevel@tonic-gate case EEXIST: 18867c478bd9Sstevel@tonic-gate err = "entry exists"; 18877c478bd9Sstevel@tonic-gate break; 18887c478bd9Sstevel@tonic-gate case EPERM: 18897c478bd9Sstevel@tonic-gate err = "insufficient privileges"; 18907c478bd9Sstevel@tonic-gate break; 18917c478bd9Sstevel@tonic-gate default: 18927c478bd9Sstevel@tonic-gate err = strerror(oerrno); 18937c478bd9Sstevel@tonic-gate break; 18947c478bd9Sstevel@tonic-gate } 18957c478bd9Sstevel@tonic-gate (void) printf(": %s\n", err); 18967c478bd9Sstevel@tonic-gate } 1897a59fa508Sjl138328 1898a59fa508Sjl138328 del_rtcmd_irep(newrt); 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate return (oerrno); 1901a59fa508Sjl138328 #undef hp 19027c478bd9Sstevel@tonic-gate } 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate /* 19067c478bd9Sstevel@tonic-gate * Convert a network number to the corresponding IP address. 19077c478bd9Sstevel@tonic-gate * If the RTA_NETMASK hasn't been specified yet set it based 19087c478bd9Sstevel@tonic-gate * on the class of address. 19097c478bd9Sstevel@tonic-gate */ 19107c478bd9Sstevel@tonic-gate static void 1911a59fa508Sjl138328 inet_makenetandmask(rtcmd_irep_t *rcip, in_addr_t net, struct sockaddr_in *sin) 19127c478bd9Sstevel@tonic-gate { 19137c478bd9Sstevel@tonic-gate in_addr_t addr, mask; 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate if (net == 0) { 19167c478bd9Sstevel@tonic-gate mask = addr = 0; 19177c478bd9Sstevel@tonic-gate } else if (net < 128) { 19187c478bd9Sstevel@tonic-gate addr = net << IN_CLASSA_NSHIFT; 19197c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 19207c478bd9Sstevel@tonic-gate } else if (net < 65536) { 19217c478bd9Sstevel@tonic-gate addr = net << IN_CLASSB_NSHIFT; 19227c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 19237c478bd9Sstevel@tonic-gate } else if (net < 16777216L) { 19247c478bd9Sstevel@tonic-gate addr = net << IN_CLASSC_NSHIFT; 19257c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 19267c478bd9Sstevel@tonic-gate } else { 19277c478bd9Sstevel@tonic-gate addr = net; 19287c478bd9Sstevel@tonic-gate if ((addr & IN_CLASSA_HOST) == 0) 19297c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 19307c478bd9Sstevel@tonic-gate else if ((addr & IN_CLASSB_HOST) == 0) 19317c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 19327c478bd9Sstevel@tonic-gate else if ((addr & IN_CLASSC_HOST) == 0) 19337c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 19347c478bd9Sstevel@tonic-gate else { 19357c478bd9Sstevel@tonic-gate if (IN_CLASSA(addr)) 19367c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 19377c478bd9Sstevel@tonic-gate else if (IN_CLASSB(addr)) 19387c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 19397c478bd9Sstevel@tonic-gate else if (IN_CLASSC(addr)) 19407c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 19417c478bd9Sstevel@tonic-gate else 19427c478bd9Sstevel@tonic-gate mask = IP_HOST_MASK; 19437c478bd9Sstevel@tonic-gate mask = inet_makesubnetmask(addr, mask); 19447c478bd9Sstevel@tonic-gate } 19457c478bd9Sstevel@tonic-gate } 19467c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(addr); 19477c478bd9Sstevel@tonic-gate 19482a9459bdSsangeeta /* Class E default mask is 32 */ 19492a9459bdSsangeeta if (IN_CLASSE(addr)) 19502a9459bdSsangeeta mask = IN_CLASSE_NET; 19512a9459bdSsangeeta 1952a59fa508Sjl138328 if (!(rcip->ri_addrs & RTA_NETMASK)) { 1953a59fa508Sjl138328 rcip->ri_addrs |= RTA_NETMASK; 1954a59fa508Sjl138328 sin = &rcip->ri_mask.sin; 19557c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(mask); 19567c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 19577c478bd9Sstevel@tonic-gate } 19587c478bd9Sstevel@tonic-gate } 19597c478bd9Sstevel@tonic-gate 19607c478bd9Sstevel@tonic-gate static in_addr_t 19617c478bd9Sstevel@tonic-gate inet_makesubnetmask(in_addr_t addr, in_addr_t mask) 19627c478bd9Sstevel@tonic-gate { 19637c478bd9Sstevel@tonic-gate int n; 19647c478bd9Sstevel@tonic-gate struct ifconf ifc; 19657c478bd9Sstevel@tonic-gate struct ifreq ifreq; 19667c478bd9Sstevel@tonic-gate struct ifreq *ifr; 19677c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 19687c478bd9Sstevel@tonic-gate char *buf; 19697c478bd9Sstevel@tonic-gate int numifs; 19707c478bd9Sstevel@tonic-gate size_t bufsize; 19717c478bd9Sstevel@tonic-gate int iosoc; 19727c478bd9Sstevel@tonic-gate in_addr_t if_addr, if_mask; 19737c478bd9Sstevel@tonic-gate in_addr_t if_subnetmask = 0; 19747c478bd9Sstevel@tonic-gate short if_flags; 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate if (mask == 0) 19777c478bd9Sstevel@tonic-gate return (0); 19787c478bd9Sstevel@tonic-gate if ((iosoc = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 19797c478bd9Sstevel@tonic-gate quit("socket", errno); 19807c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFNUM, (char *)&numifs) < 0) 19817c478bd9Sstevel@tonic-gate quit("ioctl", errno); 19827c478bd9Sstevel@tonic-gate bufsize = numifs * sizeof (struct ifreq); 19837c478bd9Sstevel@tonic-gate buf = malloc(bufsize); 19847c478bd9Sstevel@tonic-gate if (buf == NULL) 19857c478bd9Sstevel@tonic-gate quit("malloc", errno); 19867c478bd9Sstevel@tonic-gate (void) memset(&ifc, 0, sizeof (ifc)); 19877c478bd9Sstevel@tonic-gate ifc.ifc_len = bufsize; 19887c478bd9Sstevel@tonic-gate ifc.ifc_buf = buf; 19897c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFCONF, (char *)&ifc) < 0) 19907c478bd9Sstevel@tonic-gate quit("ioctl (get interface configuration)", errno); 19917c478bd9Sstevel@tonic-gate /* Let's check to see if this is maybe a local subnet route. */ 19927c478bd9Sstevel@tonic-gate ifr = ifc.ifc_req; 19937c478bd9Sstevel@tonic-gate for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { 19947c478bd9Sstevel@tonic-gate ifreq = *ifr; 19957c478bd9Sstevel@tonic-gate /* LINTED */ 19967c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr->ifr_addr; 19977c478bd9Sstevel@tonic-gate if_addr = ntohl(sin->sin_addr.s_addr); 19987c478bd9Sstevel@tonic-gate 19997c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFFLAGS, (char *)&ifreq) < 0) 20007c478bd9Sstevel@tonic-gate quit("ioctl (get interface flags)", errno); 20017c478bd9Sstevel@tonic-gate if ((ifreq.ifr_flags & IFF_UP) == 0) 20027c478bd9Sstevel@tonic-gate continue; 20037c478bd9Sstevel@tonic-gate if_flags = ifreq.ifr_flags; 20047c478bd9Sstevel@tonic-gate 20057c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFNETMASK, (char *)&ifreq) < 0) 20067c478bd9Sstevel@tonic-gate quit("ioctl (get netmask)", errno); 20077c478bd9Sstevel@tonic-gate /* LINTED */ 20087c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifreq.ifr_addr; 20097c478bd9Sstevel@tonic-gate if_mask = ntohl(sin->sin_addr.s_addr); 20107c478bd9Sstevel@tonic-gate if ((if_addr & mask) == (addr & mask)) { 20117c478bd9Sstevel@tonic-gate /* 20127c478bd9Sstevel@tonic-gate * Don't trust pt-pt interfaces if there are 20137c478bd9Sstevel@tonic-gate * other interfaces. 20147c478bd9Sstevel@tonic-gate */ 20157c478bd9Sstevel@tonic-gate if (if_flags & IFF_POINTOPOINT) { 20167c478bd9Sstevel@tonic-gate if_subnetmask = if_mask; 20177c478bd9Sstevel@tonic-gate continue; 20187c478bd9Sstevel@tonic-gate } 20197c478bd9Sstevel@tonic-gate /* 20207c478bd9Sstevel@tonic-gate * Fine. Just assume the same net mask as the 20217c478bd9Sstevel@tonic-gate * directly attached subnet interface is using. 20227c478bd9Sstevel@tonic-gate */ 20237c478bd9Sstevel@tonic-gate return (if_mask); 20247c478bd9Sstevel@tonic-gate } 20257c478bd9Sstevel@tonic-gate } 20267c478bd9Sstevel@tonic-gate if (if_subnetmask != 0) 20277c478bd9Sstevel@tonic-gate return (if_subnetmask); 20287c478bd9Sstevel@tonic-gate return (mask); 20297c478bd9Sstevel@tonic-gate } 20307c478bd9Sstevel@tonic-gate 20317c478bd9Sstevel@tonic-gate /* 2032a59fa508Sjl138328 * Interpret an argument as a network address of some kind. 20337c478bd9Sstevel@tonic-gate * 20347c478bd9Sstevel@tonic-gate * If the address family is one looked up in getaddr() using one of the 20357c478bd9Sstevel@tonic-gate * getipnodebyX() functions (currently only AF_INET6), then callers should 20367c478bd9Sstevel@tonic-gate * freehostent() the returned "struct hostent" pointer if one was passed in. 2037a59fa508Sjl138328 * 2038a59fa508Sjl138328 * If exit_on_error is true, this function will cause route to exit on error by 2039a59fa508Sjl138328 * calling syntax_error(). Otherwise, it returns B_TRUE on success or B_FALSE 2040a59fa508Sjl138328 * on failure. 20417c478bd9Sstevel@tonic-gate */ 20427c478bd9Sstevel@tonic-gate static boolean_t 2043a59fa508Sjl138328 getaddr(rtcmd_irep_t *rcip, int which, char *s, addr_type_t atype) 20447c478bd9Sstevel@tonic-gate { 2045a59fa508Sjl138328 su_t *su; 2046a59fa508Sjl138328 struct hostent **hpp; 20477c478bd9Sstevel@tonic-gate struct hostent *hp; 2048a59fa508Sjl138328 int masklen; 20497c478bd9Sstevel@tonic-gate 2050a59fa508Sjl138328 if (which == RTA_GATEWAY) { 2051a59fa508Sjl138328 hpp = &(rcip->ri_gate_hp); 2052a59fa508Sjl138328 } else { 20537a23074eSdduvall hpp = &hp; 2054a59fa508Sjl138328 } 20557c478bd9Sstevel@tonic-gate *hpp = NULL; 2056a59fa508Sjl138328 2057a59fa508Sjl138328 rcip->ri_addrs |= which; 20587c478bd9Sstevel@tonic-gate switch (which) { 20597c478bd9Sstevel@tonic-gate case RTA_DST: 2060a59fa508Sjl138328 save_string(&rcip->ri_dest_str, s); 2061a59fa508Sjl138328 su = &rcip->ri_dst; 2062a59fa508Sjl138328 su->sa.sa_family = rcip->ri_af; 20637c478bd9Sstevel@tonic-gate break; 20647c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 2065a59fa508Sjl138328 save_string(&rcip->ri_gate_str, s); 2066a59fa508Sjl138328 su = &rcip->ri_gate; 2067a59fa508Sjl138328 su->sa.sa_family = rcip->ri_af; 20687c478bd9Sstevel@tonic-gate break; 20697c478bd9Sstevel@tonic-gate case RTA_NETMASK: 2070a59fa508Sjl138328 su = &rcip->ri_mask; 2071a59fa508Sjl138328 su->sa.sa_family = rcip->ri_af; 20727c478bd9Sstevel@tonic-gate break; 20737c478bd9Sstevel@tonic-gate case RTA_IFP: 2074a59fa508Sjl138328 save_string(&rcip->ri_ifp_str, s); 2075a59fa508Sjl138328 return (B_TRUE); 20767c478bd9Sstevel@tonic-gate /* 20777c478bd9Sstevel@tonic-gate * RTA_SRC has overloaded meaning. It can represent the 20787c478bd9Sstevel@tonic-gate * src address of incoming or outgoing packets. 20797c478bd9Sstevel@tonic-gate */ 20807c478bd9Sstevel@tonic-gate case RTA_IFA: 2081a59fa508Sjl138328 su = &rcip->ri_ifa; 2082a59fa508Sjl138328 su->sa.sa_family = rcip->ri_af; 20837c478bd9Sstevel@tonic-gate break; 20847c478bd9Sstevel@tonic-gate case RTA_SRC: 2085a59fa508Sjl138328 su = &rcip->ri_src; 2086a59fa508Sjl138328 su->sa.sa_family = rcip->ri_af; 20877c478bd9Sstevel@tonic-gate break; 20887c478bd9Sstevel@tonic-gate default: 20897c478bd9Sstevel@tonic-gate /* NOTREACHED */ 20907c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 20917c478bd9Sstevel@tonic-gate /* NOTREACHED */ 20927c478bd9Sstevel@tonic-gate } 20937c478bd9Sstevel@tonic-gate if (strcmp(s, "default") == 0) { 20947c478bd9Sstevel@tonic-gate if (which == RTA_DST) { 2095a59fa508Sjl138328 return (getaddr(rcip, RTA_NETMASK, s, ADDR_TYPE_NET)); 20967c478bd9Sstevel@tonic-gate } 20977c478bd9Sstevel@tonic-gate if (which == RTA_SRC) { 20987c478bd9Sstevel@tonic-gate return (B_TRUE); 20997c478bd9Sstevel@tonic-gate } 2100a59fa508Sjl138328 return (B_TRUE); 21017c478bd9Sstevel@tonic-gate } 2102a59fa508Sjl138328 switch (rcip->ri_af) { 21037c478bd9Sstevel@tonic-gate case AF_LINK: 21047c478bd9Sstevel@tonic-gate link_addr(s, &su->sdl); 21057c478bd9Sstevel@tonic-gate return (B_TRUE); 21067c478bd9Sstevel@tonic-gate case PF_ROUTE: 21077c478bd9Sstevel@tonic-gate sockaddr(s, &su->sa); 21087c478bd9Sstevel@tonic-gate return (B_TRUE); 21097c478bd9Sstevel@tonic-gate case AF_INET6: 21107c478bd9Sstevel@tonic-gate switch (which) { 21117c478bd9Sstevel@tonic-gate case RTA_DST: 2112a59fa508Sjl138328 if (!in6_getaddr(s, &su->sin6, &masklen, hpp)) { 2113a59fa508Sjl138328 return (B_FALSE); 21147c478bd9Sstevel@tonic-gate } 2115a59fa508Sjl138328 if (masklen != NO_PREFIX) { 2116a59fa508Sjl138328 (void) memset(&rcip->ri_mask.sin6.sin6_addr, 0, 2117a59fa508Sjl138328 sizeof (rcip->ri_mask.sin6.sin6_addr)); 21187a23074eSdduvall if (!in_prefixlentomask(masklen, IPV6_ABITS, 2119a59fa508Sjl138328 (uchar_t *)&rcip->ri_mask.sin6.sin6_addr)) { 2120a59fa508Sjl138328 syntax_error(gettext( 2121a59fa508Sjl138328 "route: bad prefix length: %d\n"), 2122a59fa508Sjl138328 masklen); 2123a59fa508Sjl138328 return (B_FALSE); 21247c478bd9Sstevel@tonic-gate } 2125a59fa508Sjl138328 rcip->ri_mask.sin6.sin6_family = rcip->ri_af; 2126a59fa508Sjl138328 rcip->ri_addrs |= RTA_NETMASK; 21277c478bd9Sstevel@tonic-gate } 2128a59fa508Sjl138328 return (B_TRUE); 21297c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 21307c478bd9Sstevel@tonic-gate case RTA_IFA: 21317c478bd9Sstevel@tonic-gate case RTA_SRC: 2132a59fa508Sjl138328 return (in6_getaddr(s, &su->sin6, NULL, hpp)); 21337c478bd9Sstevel@tonic-gate case RTA_NETMASK: 2134a59fa508Sjl138328 syntax_error( 21357c478bd9Sstevel@tonic-gate gettext("route: -netmask not supported for IPv6: " 2136a59fa508Sjl138328 "use <prefix>/<prefix-length> instead\n")); 2137a59fa508Sjl138328 return (B_FALSE); 21387c478bd9Sstevel@tonic-gate default: 21397c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 21407c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21417c478bd9Sstevel@tonic-gate } 21427c478bd9Sstevel@tonic-gate case AF_INET: 21437c478bd9Sstevel@tonic-gate switch (which) { 21447c478bd9Sstevel@tonic-gate case RTA_DST: 2145a59fa508Sjl138328 if (!in_getaddr(s, &su->sin, &masklen, which, hpp, 2146a59fa508Sjl138328 atype, rcip)) { 2147a59fa508Sjl138328 return (B_FALSE); 21487c478bd9Sstevel@tonic-gate } 2149a59fa508Sjl138328 if (masklen != NO_PREFIX) { 2150a59fa508Sjl138328 (void) memset(&rcip->ri_mask.sin.sin_addr, 0, 2151a59fa508Sjl138328 sizeof (rcip->ri_mask.sin.sin_addr)); 21527a23074eSdduvall if (!in_prefixlentomask(masklen, IP_ABITS, 2153a59fa508Sjl138328 (uchar_t *)&rcip->ri_mask.sin.sin_addr)) { 2154a59fa508Sjl138328 syntax_error(gettext( 2155a59fa508Sjl138328 "route: bad prefix length: %d\n"), 2156a59fa508Sjl138328 masklen); 2157a59fa508Sjl138328 return (B_FALSE); 21587c478bd9Sstevel@tonic-gate } 2159a59fa508Sjl138328 rcip->ri_mask.sin.sin_family = rcip->ri_af; 2160a59fa508Sjl138328 rcip->ri_addrs |= RTA_NETMASK; 21617c478bd9Sstevel@tonic-gate } 2162a59fa508Sjl138328 return (B_TRUE); 21637c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 21647c478bd9Sstevel@tonic-gate case RTA_IFA: 21657c478bd9Sstevel@tonic-gate case RTA_NETMASK: 21667c478bd9Sstevel@tonic-gate case RTA_SRC: 2167a59fa508Sjl138328 return (in_getaddr(s, &su->sin, NULL, which, hpp, atype, 2168a59fa508Sjl138328 rcip)); 21697c478bd9Sstevel@tonic-gate default: 21707c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 21717c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21727c478bd9Sstevel@tonic-gate } 21737c478bd9Sstevel@tonic-gate default: 21747c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 21757c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21767c478bd9Sstevel@tonic-gate } 2177a59fa508Sjl138328 return (B_TRUE); 21787c478bd9Sstevel@tonic-gate } 21797c478bd9Sstevel@tonic-gate 21807c478bd9Sstevel@tonic-gate /* 21817c478bd9Sstevel@tonic-gate * Interpret an argument as an IPv4 network address of some kind, 2182a59fa508Sjl138328 * returning B_TRUE on success or B_FALSE on failure. 2183a59fa508Sjl138328 * This function will cause an exit() on failure if exit_on_failure is set. 2184a59fa508Sjl138328 * 2185a59fa508Sjl138328 * Note that this tries host interpretation before network interpretation, 2186a59fa508Sjl138328 * except when -net has been given and the destination address is being parsed. 21877c478bd9Sstevel@tonic-gate * 21887c478bd9Sstevel@tonic-gate * If the plenp argument is non-NULL, allow <addr>/<n> syntax and 21897c478bd9Sstevel@tonic-gate * pass out <n> in *plenp. 21907c478bd9Sstevel@tonic-gate * If <n> doesn't parse return BAD_ADDR as *plenp. 21917c478bd9Sstevel@tonic-gate * If no /<n> is present return NO_PREFIX as *plenp. 21927c478bd9Sstevel@tonic-gate */ 21937c478bd9Sstevel@tonic-gate static boolean_t 21947c478bd9Sstevel@tonic-gate in_getaddr(char *s, struct sockaddr_in *sin, int *plenp, int which, 2195a59fa508Sjl138328 struct hostent **hpp, addr_type_t atype, rtcmd_irep_t *rcip) 21967c478bd9Sstevel@tonic-gate { 21977c478bd9Sstevel@tonic-gate struct hostent *hp; 21987c478bd9Sstevel@tonic-gate struct netent *np; 21997c478bd9Sstevel@tonic-gate in_addr_t val; 22007c478bd9Sstevel@tonic-gate char str[BUFSIZ]; 22017c478bd9Sstevel@tonic-gate 2202a59fa508Sjl138328 (void) strlcpy(str, s, sizeof (str)); 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate /* 2205a59fa508Sjl138328 * If plenp is non-NULL, /<n> syntax for netmask is allowed. 22067c478bd9Sstevel@tonic-gate */ 22077c478bd9Sstevel@tonic-gate if (plenp != NULL) { 22087c478bd9Sstevel@tonic-gate char *cp; 22097c478bd9Sstevel@tonic-gate 22107c478bd9Sstevel@tonic-gate *plenp = in_getprefixlen(str, IP_ABITS); 22117c478bd9Sstevel@tonic-gate if (*plenp == BAD_ADDR) 22127c478bd9Sstevel@tonic-gate return (B_FALSE); 22137c478bd9Sstevel@tonic-gate cp = strchr(str, '/'); 22147c478bd9Sstevel@tonic-gate if (cp != NULL) 22157c478bd9Sstevel@tonic-gate *cp = '\0'; 22167c478bd9Sstevel@tonic-gate } else if (strchr(str, '/') != NULL) { 2217a59fa508Sjl138328 syntax_error(gettext("route: %s: unexpected '/'\n"), str); 2218a59fa508Sjl138328 return (B_FALSE); 22197c478bd9Sstevel@tonic-gate } 22207c478bd9Sstevel@tonic-gate 22217c478bd9Sstevel@tonic-gate (void) memset(sin, 0, sizeof (*sin)); 22227c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 22237c478bd9Sstevel@tonic-gate 22247c478bd9Sstevel@tonic-gate /* 2225a59fa508Sjl138328 * Handle 255.255.255.255 as a special case first. 22267c478bd9Sstevel@tonic-gate */ 2227a59fa508Sjl138328 if (strcmp(str, "255.255.255.255") == 0) { 2228a59fa508Sjl138328 sin->sin_addr.s_addr = INADDR_BROADCAST; 22297c478bd9Sstevel@tonic-gate return (B_TRUE); 22307c478bd9Sstevel@tonic-gate } 2231a59fa508Sjl138328 2232a59fa508Sjl138328 val = inet_addr(str); 2233a59fa508Sjl138328 if (val != (in_addr_t)-1) { 2234a59fa508Sjl138328 /* Numeric address */ 2235a59fa508Sjl138328 sin->sin_addr.s_addr = val; 2236a59fa508Sjl138328 if (which == RTA_DST) { 2237a59fa508Sjl138328 if (atype == ADDR_TYPE_NET || 2238a59fa508Sjl138328 (atype == ADDR_TYPE_ANY && 2239a59fa508Sjl138328 inet_lnaof(sin->sin_addr) == INADDR_ANY)) { 2240a59fa508Sjl138328 /* This looks like a network address. */ 2241a59fa508Sjl138328 inet_makenetandmask(rcip, ntohl(val), 2242a59fa508Sjl138328 sin); 22437c478bd9Sstevel@tonic-gate } 2244a59fa508Sjl138328 } 2245a59fa508Sjl138328 return (B_TRUE); 2246a59fa508Sjl138328 } 2247a59fa508Sjl138328 /* Host or net name */ 2248a59fa508Sjl138328 if (which != RTA_DST || atype != ADDR_TYPE_NET) { 2249a59fa508Sjl138328 /* A host name is allowed. */ 2250a59fa508Sjl138328 if ((hp = gethostbyname(str)) != NULL) { 22517c478bd9Sstevel@tonic-gate *hpp = hp; 22527c478bd9Sstevel@tonic-gate (void) memmove(&sin->sin_addr, hp->h_addr, 22537c478bd9Sstevel@tonic-gate hp->h_length); 22547c478bd9Sstevel@tonic-gate return (B_TRUE); 22557c478bd9Sstevel@tonic-gate } 22567c478bd9Sstevel@tonic-gate } 2257a59fa508Sjl138328 if (atype != ADDR_TYPE_HOST) { 2258a59fa508Sjl138328 /* A network name is allowed */ 2259a59fa508Sjl138328 if ((np = getnetbyname(str)) != NULL && 2260a59fa508Sjl138328 (val = np->n_net) != 0) { 2261a59fa508Sjl138328 if (which == RTA_DST) { 2262a59fa508Sjl138328 inet_makenetandmask(rcip, val, sin); 2263a59fa508Sjl138328 } 2264a59fa508Sjl138328 return (B_TRUE); 2265a59fa508Sjl138328 } 2266a59fa508Sjl138328 } 2267a59fa508Sjl138328 syntax_error(gettext("%s: bad value\n"), s); 2268a59fa508Sjl138328 return (B_FALSE); 22697a23074eSdduvall } 22707c478bd9Sstevel@tonic-gate 22717c478bd9Sstevel@tonic-gate /* 22727c478bd9Sstevel@tonic-gate * Interpret an argument as an IPv6 network address of some kind, 2273a59fa508Sjl138328 * returning B_TRUE on success or B_FALSE on failure. 2274a59fa508Sjl138328 * This function will cause an exit() on failure if exit_on_failure is set. 22757c478bd9Sstevel@tonic-gate * 22767c478bd9Sstevel@tonic-gate * If the last argument is non-NULL allow a <addr>/<n> syntax and 22777c478bd9Sstevel@tonic-gate * pass out <n> in *plenp. 22787c478bd9Sstevel@tonic-gate * If <n> doesn't parse return BAD_ADDR as *plenp. 22797c478bd9Sstevel@tonic-gate * If no /<n> is present return NO_PREFIX as *plenp. 22807c478bd9Sstevel@tonic-gate */ 22817c478bd9Sstevel@tonic-gate static boolean_t 22827c478bd9Sstevel@tonic-gate in6_getaddr(char *s, struct sockaddr_in6 *sin6, int *plenp, 22837c478bd9Sstevel@tonic-gate struct hostent **hpp) 22847c478bd9Sstevel@tonic-gate { 22857c478bd9Sstevel@tonic-gate struct hostent *hp; 22867c478bd9Sstevel@tonic-gate char str[BUFSIZ]; 22877c478bd9Sstevel@tonic-gate int error_num; 22887c478bd9Sstevel@tonic-gate 2289a59fa508Sjl138328 (void) strlcpy(str, s, sizeof (str)); 22907c478bd9Sstevel@tonic-gate 22917c478bd9Sstevel@tonic-gate /* 2292a59fa508Sjl138328 * If plenp is non-NULL, /<n> syntax for netmask is allowed. 22937c478bd9Sstevel@tonic-gate */ 22947c478bd9Sstevel@tonic-gate if (plenp != NULL) { 22957c478bd9Sstevel@tonic-gate char *cp; 22967c478bd9Sstevel@tonic-gate 22977c478bd9Sstevel@tonic-gate *plenp = in_getprefixlen(str, IPV6_ABITS); 22987c478bd9Sstevel@tonic-gate if (*plenp == BAD_ADDR) 22997c478bd9Sstevel@tonic-gate return (B_FALSE); 23007c478bd9Sstevel@tonic-gate cp = strchr(str, '/'); 23017c478bd9Sstevel@tonic-gate if (cp != NULL) 23027c478bd9Sstevel@tonic-gate *cp = '\0'; 23037c478bd9Sstevel@tonic-gate } else if (strchr(str, '/') != NULL) { 2304a59fa508Sjl138328 syntax_error(gettext("route: %s: unexpected '/'\n"), str); 2305a59fa508Sjl138328 return (B_FALSE); 23067c478bd9Sstevel@tonic-gate } 23077c478bd9Sstevel@tonic-gate 23087c478bd9Sstevel@tonic-gate (void) memset(sin6, 0, sizeof (struct sockaddr_in6)); 23097c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 23107c478bd9Sstevel@tonic-gate 23117c478bd9Sstevel@tonic-gate hp = getipnodebyname(str, AF_INET6, 0, &error_num); 23127c478bd9Sstevel@tonic-gate if (hp != NULL) { 23137c478bd9Sstevel@tonic-gate *hpp = hp; 23147c478bd9Sstevel@tonic-gate (void) memmove(&sin6->sin6_addr, hp->h_addr, hp->h_length); 23157c478bd9Sstevel@tonic-gate return (B_TRUE); 23167c478bd9Sstevel@tonic-gate } 23177c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 2318a59fa508Sjl138328 /* 2319a59fa508Sjl138328 * This isn't a problem if we aren't going to use the address 2320a59fa508Sjl138328 * right away. 2321a59fa508Sjl138328 */ 2322a59fa508Sjl138328 if (!exit_on_error) { 2323a59fa508Sjl138328 return (B_TRUE); 23243f33f4f7Sjl138328 } 2325a59fa508Sjl138328 syntax_error(gettext("route: %s: bad address (try " 2326a59fa508Sjl138328 "again later)\n"), s); 2327a59fa508Sjl138328 return (B_FALSE); 2328a59fa508Sjl138328 } 2329a59fa508Sjl138328 syntax_error(gettext("route: %s: bad address\n"), s); 2330a59fa508Sjl138328 return (B_FALSE); 23317c478bd9Sstevel@tonic-gate } 23327c478bd9Sstevel@tonic-gate 23337c478bd9Sstevel@tonic-gate /* 2334a59fa508Sjl138328 * Parse <addr>/<n> syntax and return the integer n. 2335a59fa508Sjl138328 * If <addr> is missing or <n> is not a valid integer, this function calls 2336a59fa508Sjl138328 * syntax_error() and returns BAD_ADDR. 2337a59fa508Sjl138328 * if n is not between 0 and max_plen inclusive, this functions calls 2338a59fa508Sjl138328 * syntax_error() and returns BAD_ADDR. 2339a59fa508Sjl138328 * If /<n> is not present, this function returns NO_PREFIX. 2340a59fa508Sjl138328 * The string addr is not modified. 23417c478bd9Sstevel@tonic-gate */ 23427c478bd9Sstevel@tonic-gate int 23437c478bd9Sstevel@tonic-gate in_getprefixlen(char *addr, int max_plen) 23447c478bd9Sstevel@tonic-gate { 23457c478bd9Sstevel@tonic-gate int prefixlen; 23467c478bd9Sstevel@tonic-gate char *str, *end; 23477c478bd9Sstevel@tonic-gate 23487c478bd9Sstevel@tonic-gate str = strchr(addr, '/'); 2349a59fa508Sjl138328 if (str == addr) { 2350a59fa508Sjl138328 syntax_error(gettext("route: %s: unexpected '/'\n"), addr); 2351a59fa508Sjl138328 return (BAD_ADDR); 2352a59fa508Sjl138328 } 23537c478bd9Sstevel@tonic-gate if (str == NULL) 23547c478bd9Sstevel@tonic-gate return (NO_PREFIX); 23557c478bd9Sstevel@tonic-gate str++; 23567c478bd9Sstevel@tonic-gate 2357a59fa508Sjl138328 errno = 0; 2358a59fa508Sjl138328 prefixlen = strtoul(str, &end, 10); 2359a59fa508Sjl138328 if (errno != 0 || str == end) { 2360a59fa508Sjl138328 syntax_error(gettext("route: bad prefix length %s\n"), str); 23617c478bd9Sstevel@tonic-gate return (BAD_ADDR); 2362a59fa508Sjl138328 } 2363a59fa508Sjl138328 if (prefixlen > max_plen) { 2364a59fa508Sjl138328 syntax_error(gettext("route: prefix length %s out of range\n"), 2365a59fa508Sjl138328 str); 23667c478bd9Sstevel@tonic-gate return (BAD_ADDR); 2367a59fa508Sjl138328 } 23687c478bd9Sstevel@tonic-gate return (prefixlen); 23697c478bd9Sstevel@tonic-gate } 23707c478bd9Sstevel@tonic-gate 23717c478bd9Sstevel@tonic-gate /* 23727c478bd9Sstevel@tonic-gate * Convert a prefix length to a mask. 23737c478bd9Sstevel@tonic-gate * Returns B_TRUE if ok. B_FALSE otherwise. 23747c478bd9Sstevel@tonic-gate * Assumes the mask array is zeroed by the caller. 23757c478bd9Sstevel@tonic-gate */ 23767c478bd9Sstevel@tonic-gate boolean_t 23777c478bd9Sstevel@tonic-gate in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 23787c478bd9Sstevel@tonic-gate { 23797c478bd9Sstevel@tonic-gate if (prefixlen < 0 || prefixlen > maxlen) 23807c478bd9Sstevel@tonic-gate return (B_FALSE); 23817c478bd9Sstevel@tonic-gate 23827c478bd9Sstevel@tonic-gate while (prefixlen > 0) { 23837c478bd9Sstevel@tonic-gate if (prefixlen >= 8) { 23847c478bd9Sstevel@tonic-gate *mask++ = 0xFF; 23857c478bd9Sstevel@tonic-gate prefixlen -= 8; 23867c478bd9Sstevel@tonic-gate continue; 23877c478bd9Sstevel@tonic-gate } 23887c478bd9Sstevel@tonic-gate *mask |= 1 << (8 - prefixlen); 23897c478bd9Sstevel@tonic-gate prefixlen--; 23907c478bd9Sstevel@tonic-gate } 23917c478bd9Sstevel@tonic-gate return (B_TRUE); 23927c478bd9Sstevel@tonic-gate } 23937c478bd9Sstevel@tonic-gate 23947c478bd9Sstevel@tonic-gate void 23957c478bd9Sstevel@tonic-gate rtmonitor(int argc, char *argv[]) 23967c478bd9Sstevel@tonic-gate { 23977c478bd9Sstevel@tonic-gate int n; 23987c478bd9Sstevel@tonic-gate intmax_t msg[2048 / sizeof (intmax_t)]; 23997c478bd9Sstevel@tonic-gate 24007c478bd9Sstevel@tonic-gate if (tflag) 24017c478bd9Sstevel@tonic-gate exit(0); 24027c478bd9Sstevel@tonic-gate verbose = B_TRUE; 24037c478bd9Sstevel@tonic-gate if (argc > 1) { 24047c478bd9Sstevel@tonic-gate argv++; 24057c478bd9Sstevel@tonic-gate if (argc == 2 && **argv == '-') { 24067c478bd9Sstevel@tonic-gate switch (keyword(*argv + 1)) { 24077c478bd9Sstevel@tonic-gate case K_INET: 24087c478bd9Sstevel@tonic-gate af = AF_INET; 24097c478bd9Sstevel@tonic-gate break; 24107c478bd9Sstevel@tonic-gate case K_LINK: 24117c478bd9Sstevel@tonic-gate af = AF_LINK; 24127c478bd9Sstevel@tonic-gate break; 24137c478bd9Sstevel@tonic-gate case K_INET6: 24147c478bd9Sstevel@tonic-gate af = AF_INET6; 24157c478bd9Sstevel@tonic-gate break; 24167c478bd9Sstevel@tonic-gate default: 24177c478bd9Sstevel@tonic-gate usage(*argv); 24187c478bd9Sstevel@tonic-gate /* NOTREACHED */ 24197c478bd9Sstevel@tonic-gate } 24207c478bd9Sstevel@tonic-gate } else { 24217c478bd9Sstevel@tonic-gate usage(*argv); 24227c478bd9Sstevel@tonic-gate } 24237c478bd9Sstevel@tonic-gate (void) close(s); 24247c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, af); 24257c478bd9Sstevel@tonic-gate if (s < 0) 24267c478bd9Sstevel@tonic-gate quit("socket", errno); 24277c478bd9Sstevel@tonic-gate } 24287c478bd9Sstevel@tonic-gate for (;;) { 24297c478bd9Sstevel@tonic-gate n = read(s, msg, sizeof (msg)); 24307c478bd9Sstevel@tonic-gate if (n <= 0) 24317c478bd9Sstevel@tonic-gate quit("read", errno); 24327c478bd9Sstevel@tonic-gate (void) printf("got message of size %d\n", n); 24337c478bd9Sstevel@tonic-gate print_rtmsg((struct rt_msghdr *)msg, n); 24347c478bd9Sstevel@tonic-gate } 24357c478bd9Sstevel@tonic-gate } 24367c478bd9Sstevel@tonic-gate 24377c478bd9Sstevel@tonic-gate int 2438a59fa508Sjl138328 rtmsg(rtcmd_irep_t *newrt) 24397c478bd9Sstevel@tonic-gate { 24407c478bd9Sstevel@tonic-gate static int seq; 24417c478bd9Sstevel@tonic-gate int rlen; 24427c478bd9Sstevel@tonic-gate char *cp = m_rtmsg.m_space; 24437c478bd9Sstevel@tonic-gate int l; 24447c478bd9Sstevel@tonic-gate 24457c478bd9Sstevel@tonic-gate errno = 0; 24467c478bd9Sstevel@tonic-gate (void) memset(&m_rtmsg, 0, sizeof (m_rtmsg)); 2447a59fa508Sjl138328 2448a59fa508Sjl138328 if (newrt->ri_cmd == RTM_GET) { 2449a59fa508Sjl138328 newrt->ri_ifp.sa.sa_family = AF_LINK; 2450a59fa508Sjl138328 newrt->ri_addrs |= RTA_IFP; 24517c478bd9Sstevel@tonic-gate } 2452a59fa508Sjl138328 24537c478bd9Sstevel@tonic-gate #define rtm m_rtmsg.m_rtm 2454a59fa508Sjl138328 rtm.rtm_type = newrt->ri_cmd; 2455a59fa508Sjl138328 rtm.rtm_flags = newrt->ri_flags; 24567c478bd9Sstevel@tonic-gate rtm.rtm_version = RTM_VERSION; 24577c478bd9Sstevel@tonic-gate rtm.rtm_seq = ++seq; 2458a59fa508Sjl138328 rtm.rtm_addrs = newrt->ri_addrs; 2459a59fa508Sjl138328 rtm.rtm_rmx = newrt->ri_metrics; 2460a59fa508Sjl138328 rtm.rtm_inits = newrt->ri_inits; 24617c478bd9Sstevel@tonic-gate 24627c478bd9Sstevel@tonic-gate #define NEXTADDR(w, u) \ 2463a59fa508Sjl138328 if (newrt->ri_addrs & (w)) { \ 24647c478bd9Sstevel@tonic-gate l = ROUNDUP_LONG(salen(&u.sa)); \ 24657c478bd9Sstevel@tonic-gate (void) memmove(cp, &(u), l); \ 24667c478bd9Sstevel@tonic-gate cp += l; \ 24677c478bd9Sstevel@tonic-gate if (verbose) \ 24687c478bd9Sstevel@tonic-gate sodump(&(u), #u); \ 24697c478bd9Sstevel@tonic-gate } 2470a59fa508Sjl138328 NEXTADDR(RTA_DST, newrt->ri_dst); 2471a59fa508Sjl138328 NEXTADDR(RTA_GATEWAY, newrt->ri_gate); 2472a59fa508Sjl138328 NEXTADDR(RTA_NETMASK, newrt->ri_mask); 2473a59fa508Sjl138328 NEXTADDR(RTA_IFP, newrt->ri_ifp); 2474a59fa508Sjl138328 NEXTADDR(RTA_IFA, newrt->ri_ifa); 24757c478bd9Sstevel@tonic-gate /* 24767c478bd9Sstevel@tonic-gate * RTA_SRC has overloaded meaning. It can represent the 24777c478bd9Sstevel@tonic-gate * src address of incoming or outgoing packets. 24787c478bd9Sstevel@tonic-gate */ 2479a59fa508Sjl138328 NEXTADDR(RTA_SRC, newrt->ri_src); 24807c478bd9Sstevel@tonic-gate #undef NEXTADDR 248145916cd2Sjpk 248245916cd2Sjpk if (newrt->ri_rtsa_cnt > 0) { 248345916cd2Sjpk /* LINTED: aligned */ 248445916cd2Sjpk rtm_ext_t *rtm_ext = (rtm_ext_t *)cp; 248545916cd2Sjpk tsol_rtsecattr_t *rtsecattr; 248645916cd2Sjpk 248745916cd2Sjpk rtm_ext->rtmex_type = RTMEX_GATEWAY_SECATTR; 248845916cd2Sjpk rtm_ext->rtmex_len = TSOL_RTSECATTR_SIZE(1); 248945916cd2Sjpk 249045916cd2Sjpk rtsecattr = (tsol_rtsecattr_t *)(rtm_ext + 1); 249145916cd2Sjpk rtsecattr->rtsa_cnt = 1; 249245916cd2Sjpk 249345916cd2Sjpk bcopy(&newrt->ri_rtsa, rtsecattr->rtsa_attr, 249445916cd2Sjpk sizeof (newrt->ri_rtsa)); 249545916cd2Sjpk cp = (char *)(rtsecattr->rtsa_attr + 1); 249645916cd2Sjpk } 249745916cd2Sjpk 24987c478bd9Sstevel@tonic-gate rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 249945916cd2Sjpk 25007c478bd9Sstevel@tonic-gate if (verbose) 25017c478bd9Sstevel@tonic-gate print_rtmsg(&rtm, l); 25027c478bd9Sstevel@tonic-gate if (debugonly) 25037c478bd9Sstevel@tonic-gate return (0); 25047c478bd9Sstevel@tonic-gate if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 25057c478bd9Sstevel@tonic-gate switch (errno) { 25067c478bd9Sstevel@tonic-gate case ESRCH: 25077c478bd9Sstevel@tonic-gate case EBUSY: 25087c478bd9Sstevel@tonic-gate case ENOBUFS: 25097c478bd9Sstevel@tonic-gate case EEXIST: 25107c478bd9Sstevel@tonic-gate case ENETUNREACH: 25117c478bd9Sstevel@tonic-gate case EHOSTUNREACH: 25127c478bd9Sstevel@tonic-gate case EPERM: 25137c478bd9Sstevel@tonic-gate break; 25147c478bd9Sstevel@tonic-gate default: 25157c478bd9Sstevel@tonic-gate perror(gettext("writing to routing socket")); 25167c478bd9Sstevel@tonic-gate break; 25177c478bd9Sstevel@tonic-gate } 25187c478bd9Sstevel@tonic-gate return (-1); 25197c478bd9Sstevel@tonic-gate } else if (rlen < (int)rtm.rtm_msglen) { 25207c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 25217c478bd9Sstevel@tonic-gate gettext("route: write to routing socket got only %d for " 25227c478bd9Sstevel@tonic-gate "len\n"), rlen); 25237c478bd9Sstevel@tonic-gate return (-1); 25247c478bd9Sstevel@tonic-gate } 2525a59fa508Sjl138328 if (newrt->ri_cmd == RTM_GET) { 25267c478bd9Sstevel@tonic-gate do { 25277c478bd9Sstevel@tonic-gate l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg)); 25287c478bd9Sstevel@tonic-gate } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 25297c478bd9Sstevel@tonic-gate if (l < 0) { 25307c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 25317c478bd9Sstevel@tonic-gate gettext("route: read from routing socket: %s\n"), 25327c478bd9Sstevel@tonic-gate strerror(errno)); 25337c478bd9Sstevel@tonic-gate } else { 2534a59fa508Sjl138328 print_getmsg(newrt, &rtm, l); 25357c478bd9Sstevel@tonic-gate } 25367c478bd9Sstevel@tonic-gate } 25377c478bd9Sstevel@tonic-gate #undef rtm 25387c478bd9Sstevel@tonic-gate return (0); 25397c478bd9Sstevel@tonic-gate } 25407c478bd9Sstevel@tonic-gate 25417c478bd9Sstevel@tonic-gate static char *msgtypes[] = { 25427c478bd9Sstevel@tonic-gate "", 25437c478bd9Sstevel@tonic-gate "RTM_ADD: Add Route", 25447c478bd9Sstevel@tonic-gate "RTM_DELETE: Delete Route", 25457c478bd9Sstevel@tonic-gate "RTM_CHANGE: Change Metrics or flags", 25467c478bd9Sstevel@tonic-gate "RTM_GET: Report Metrics", 25477c478bd9Sstevel@tonic-gate "RTM_LOSING: Kernel Suspects Partitioning", 25487c478bd9Sstevel@tonic-gate "RTM_REDIRECT: Told to use different route", 25497c478bd9Sstevel@tonic-gate "RTM_MISS: Lookup failed on this address", 25507c478bd9Sstevel@tonic-gate "RTM_LOCK: fix specified metrics", 25517c478bd9Sstevel@tonic-gate "RTM_OLDADD: caused by SIOCADDRT", 25527c478bd9Sstevel@tonic-gate "RTM_OLDDEL: caused by SIOCDELRT", 25537c478bd9Sstevel@tonic-gate "RTM_RESOLVE: Route created by cloning", 25547c478bd9Sstevel@tonic-gate "RTM_NEWADDR: address being added to iface", 25557c478bd9Sstevel@tonic-gate "RTM_DELADDR: address being removed from iface", 25567c478bd9Sstevel@tonic-gate "RTM_IFINFO: iface status change", 25577c478bd9Sstevel@tonic-gate 0, 25587c478bd9Sstevel@tonic-gate }; 25597c478bd9Sstevel@tonic-gate 25607c478bd9Sstevel@tonic-gate #define NMSGTYPES (sizeof (msgtypes) / sizeof (msgtypes[0])) 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate static char metricnames[] = 25637c478bd9Sstevel@tonic-gate "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount" 25647c478bd9Sstevel@tonic-gate "\1mtu"; 25657c478bd9Sstevel@tonic-gate static char routeflags[] = 25667c478bd9Sstevel@tonic-gate "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT" 25677c478bd9Sstevel@tonic-gate "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 2568*bd670b35SErik Nordmark "\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC\023INDIRECT"; 25697c478bd9Sstevel@tonic-gate static char ifnetflags[] = 25707c478bd9Sstevel@tonic-gate "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP" 25717c478bd9Sstevel@tonic-gate "\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST" 25727c478bd9Sstevel@tonic-gate "\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE" 25737c478bd9Sstevel@tonic-gate "\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF" 25747c478bd9Sstevel@tonic-gate "\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6" 25755c0b7edeSseb "\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE" 25765c0b7edeSseb "\041XRESOLV\042COS\043PREFERRED\044TEMPORARY\045FIXEDMTU\046VIRTUAL" 25775c0b7edeSseb "\047DUPLICATE"; 25787c478bd9Sstevel@tonic-gate static char addrnames[] = 25797c478bd9Sstevel@tonic-gate "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC"; 25807c478bd9Sstevel@tonic-gate 25817c478bd9Sstevel@tonic-gate void 25827c478bd9Sstevel@tonic-gate print_rtmsg(struct rt_msghdr *rtm, int msglen) 25837c478bd9Sstevel@tonic-gate { 25847c478bd9Sstevel@tonic-gate struct if_msghdr *ifm; 25857c478bd9Sstevel@tonic-gate struct ifa_msghdr *ifam; 25867c478bd9Sstevel@tonic-gate 25877c478bd9Sstevel@tonic-gate if (!verbose) 25887c478bd9Sstevel@tonic-gate return; 25897c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 25907c478bd9Sstevel@tonic-gate (void) printf("routing message version %d not understood\n", 25917c478bd9Sstevel@tonic-gate rtm->rtm_version); 25927c478bd9Sstevel@tonic-gate return; 25937c478bd9Sstevel@tonic-gate } 259445916cd2Sjpk if (rtm->rtm_msglen != msglen) { 25957c478bd9Sstevel@tonic-gate (void) printf("message length mismatch, in packet %d, " 25967c478bd9Sstevel@tonic-gate "returned %d\n", 25977c478bd9Sstevel@tonic-gate rtm->rtm_msglen, msglen); 259845916cd2Sjpk if (msglen > rtm->rtm_msglen) 259945916cd2Sjpk msglen = rtm->rtm_msglen; 26007c478bd9Sstevel@tonic-gate } 26017c478bd9Sstevel@tonic-gate /* 26027c478bd9Sstevel@tonic-gate * Since rtm->rtm_type is unsigned, we'll just check the case of zero 26037c478bd9Sstevel@tonic-gate * and the upper-bound of (NMSGTYPES - 1). 26047c478bd9Sstevel@tonic-gate */ 26057c478bd9Sstevel@tonic-gate if (rtm->rtm_type == 0 || rtm->rtm_type >= (NMSGTYPES - 1)) { 26067c478bd9Sstevel@tonic-gate (void) printf("routing message type %d not understood\n", 26077c478bd9Sstevel@tonic-gate rtm->rtm_type); 26087c478bd9Sstevel@tonic-gate return; 26097c478bd9Sstevel@tonic-gate } 261045916cd2Sjpk (void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], msglen); 26117c478bd9Sstevel@tonic-gate switch (rtm->rtm_type) { 26127c478bd9Sstevel@tonic-gate case RTM_IFINFO: 26137c478bd9Sstevel@tonic-gate ifm = (struct if_msghdr *)rtm; 26147c478bd9Sstevel@tonic-gate (void) printf("if# %d, flags:", ifm->ifm_index); 26157c478bd9Sstevel@tonic-gate bprintf(stdout, ifm->ifm_flags, ifnetflags); 261645916cd2Sjpk pmsg_addrs((const char *)(ifm + 1), msglen - sizeof (*ifm), 261745916cd2Sjpk ifm->ifm_addrs); 26187c478bd9Sstevel@tonic-gate break; 26197c478bd9Sstevel@tonic-gate case RTM_NEWADDR: 26207c478bd9Sstevel@tonic-gate case RTM_DELADDR: 26217c478bd9Sstevel@tonic-gate ifam = (struct ifa_msghdr *)rtm; 26227c478bd9Sstevel@tonic-gate (void) printf("metric %d, flags:", ifam->ifam_metric); 26237c478bd9Sstevel@tonic-gate bprintf(stdout, ifam->ifam_flags, routeflags); 262445916cd2Sjpk pmsg_addrs((const char *)(ifam + 1), msglen - sizeof (*ifam), 262545916cd2Sjpk ifam->ifam_addrs); 26267c478bd9Sstevel@tonic-gate break; 26277c478bd9Sstevel@tonic-gate default: 26287c478bd9Sstevel@tonic-gate (void) printf("pid: %ld, seq %d, errno %d, flags:", 26297c478bd9Sstevel@tonic-gate rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 26307c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_flags, routeflags); 263145916cd2Sjpk pmsg_common(rtm, msglen); 263245916cd2Sjpk break; 26337c478bd9Sstevel@tonic-gate } 26347c478bd9Sstevel@tonic-gate } 26357c478bd9Sstevel@tonic-gate 26367c478bd9Sstevel@tonic-gate void 2637a59fa508Sjl138328 print_getmsg(rtcmd_irep_t *req_rt, struct rt_msghdr *rtm, int msglen) 26387c478bd9Sstevel@tonic-gate { 26397c478bd9Sstevel@tonic-gate struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL; 26407c478bd9Sstevel@tonic-gate struct sockaddr_dl *ifp = NULL; 26417c478bd9Sstevel@tonic-gate struct sockaddr *sa; 26427c478bd9Sstevel@tonic-gate char *cp; 26437c478bd9Sstevel@tonic-gate int i; 26447c478bd9Sstevel@tonic-gate 2645a59fa508Sjl138328 (void) printf(" route to: %s\n", routename(&req_rt->ri_dst.sa)); 26467c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 26477c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 26487c478bd9Sstevel@tonic-gate gettext("routing message version %d not understood\n"), 26497c478bd9Sstevel@tonic-gate rtm->rtm_version); 26507c478bd9Sstevel@tonic-gate return; 26517c478bd9Sstevel@tonic-gate } 26527c478bd9Sstevel@tonic-gate if (rtm->rtm_msglen > (ushort_t)msglen) { 26537c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 26547c478bd9Sstevel@tonic-gate gettext("message length mismatch, in packet %d, " 26557c478bd9Sstevel@tonic-gate "returned %d\n"), rtm->rtm_msglen, msglen); 26567c478bd9Sstevel@tonic-gate } 26577c478bd9Sstevel@tonic-gate if (rtm->rtm_errno) { 26587c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "RTM_GET: %s (errno %d)\n", 26597c478bd9Sstevel@tonic-gate strerror(rtm->rtm_errno), rtm->rtm_errno); 26607c478bd9Sstevel@tonic-gate return; 26617c478bd9Sstevel@tonic-gate } 26627c478bd9Sstevel@tonic-gate cp = ((char *)(rtm + 1)); 26637c478bd9Sstevel@tonic-gate if (rtm->rtm_addrs != 0) { 26647c478bd9Sstevel@tonic-gate for (i = 1; i != 0; i <<= 1) { 26657c478bd9Sstevel@tonic-gate if (i & rtm->rtm_addrs) { 26667c478bd9Sstevel@tonic-gate /* LINTED */ 26677c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)cp; 26687c478bd9Sstevel@tonic-gate switch (i) { 26697c478bd9Sstevel@tonic-gate case RTA_DST: 26707c478bd9Sstevel@tonic-gate dst = sa; 26717c478bd9Sstevel@tonic-gate break; 26727c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 26737c478bd9Sstevel@tonic-gate gate = sa; 26747c478bd9Sstevel@tonic-gate break; 26757c478bd9Sstevel@tonic-gate case RTA_NETMASK: 26767c478bd9Sstevel@tonic-gate mask = sa; 26777c478bd9Sstevel@tonic-gate break; 26787c478bd9Sstevel@tonic-gate case RTA_IFP: 26797c478bd9Sstevel@tonic-gate if (sa->sa_family == AF_LINK && 26807c478bd9Sstevel@tonic-gate ((struct sockaddr_dl *)sa)-> 26817c478bd9Sstevel@tonic-gate sdl_nlen != 0) 26827c478bd9Sstevel@tonic-gate ifp = (struct sockaddr_dl *)sa; 26837c478bd9Sstevel@tonic-gate break; 26847c478bd9Sstevel@tonic-gate case RTA_SRC: 26857c478bd9Sstevel@tonic-gate src = sa; 26867c478bd9Sstevel@tonic-gate break; 26877c478bd9Sstevel@tonic-gate } 26887c478bd9Sstevel@tonic-gate ADVANCE(cp, sa); 26897c478bd9Sstevel@tonic-gate } 26907c478bd9Sstevel@tonic-gate } 26917c478bd9Sstevel@tonic-gate } 26927c478bd9Sstevel@tonic-gate if (dst != NULL && mask != NULL) 26937c478bd9Sstevel@tonic-gate mask->sa_family = dst->sa_family; /* XXX */ 26947c478bd9Sstevel@tonic-gate if (dst != NULL) 26957c478bd9Sstevel@tonic-gate (void) printf("destination: %s\n", routename(dst)); 26967c478bd9Sstevel@tonic-gate if (mask != NULL) { 26977c478bd9Sstevel@tonic-gate boolean_t savenflag = nflag; 26987c478bd9Sstevel@tonic-gate 26997c478bd9Sstevel@tonic-gate nflag = B_TRUE; 27007c478bd9Sstevel@tonic-gate (void) printf(" mask: %s\n", routename(mask)); 27017c478bd9Sstevel@tonic-gate nflag = savenflag; 27027c478bd9Sstevel@tonic-gate } 27037c478bd9Sstevel@tonic-gate if (gate != NULL && rtm->rtm_flags & RTF_GATEWAY) 27047c478bd9Sstevel@tonic-gate (void) printf(" gateway: %s\n", routename(gate)); 27057c478bd9Sstevel@tonic-gate if (src != NULL && rtm->rtm_flags & RTF_SETSRC) 27067c478bd9Sstevel@tonic-gate (void) printf(" setsrc: %s\n", routename(src)); 27077c478bd9Sstevel@tonic-gate if (ifp != NULL) { 27087c478bd9Sstevel@tonic-gate if (verbose) { 27097c478bd9Sstevel@tonic-gate int i; 27107c478bd9Sstevel@tonic-gate 27117c478bd9Sstevel@tonic-gate (void) printf(" interface: %.*s index %d address ", 27127c478bd9Sstevel@tonic-gate ifp->sdl_nlen, ifp->sdl_data, ifp->sdl_index); 27137c478bd9Sstevel@tonic-gate for (i = ifp->sdl_nlen; 27147c478bd9Sstevel@tonic-gate i < ifp->sdl_nlen + ifp->sdl_alen; 27157c478bd9Sstevel@tonic-gate i++) { 27167c478bd9Sstevel@tonic-gate (void) printf("%02x ", 27177c478bd9Sstevel@tonic-gate ifp->sdl_data[i] & 0xFF); 27187c478bd9Sstevel@tonic-gate } 27197c478bd9Sstevel@tonic-gate (void) printf("\n"); 27207c478bd9Sstevel@tonic-gate } else { 27217c478bd9Sstevel@tonic-gate (void) printf(" interface: %.*s\n", 27227c478bd9Sstevel@tonic-gate ifp->sdl_nlen, ifp->sdl_data); 27237c478bd9Sstevel@tonic-gate } 27247c478bd9Sstevel@tonic-gate } 27257c478bd9Sstevel@tonic-gate (void) printf(" flags: "); 27267c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_flags, routeflags); 27277c478bd9Sstevel@tonic-gate 27287c478bd9Sstevel@tonic-gate #define lock(f) ((rtm->rtm_rmx.rmx_locks & RTV_ ## f) ? 'L' : ' ') 27297c478bd9Sstevel@tonic-gate #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 27307c478bd9Sstevel@tonic-gate 27317c478bd9Sstevel@tonic-gate (void) printf("\n%s\n", " recvpipe sendpipe ssthresh rtt,ms " 27327c478bd9Sstevel@tonic-gate "rttvar,ms hopcount mtu expire"); 27337c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 27347c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 27357c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 27367c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 27377c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 27387c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 27397c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 27407c478bd9Sstevel@tonic-gate if (rtm->rtm_rmx.rmx_expire) 27417c478bd9Sstevel@tonic-gate rtm->rtm_rmx.rmx_expire -= time(0); 274245916cd2Sjpk (void) printf("%8d%c", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 27437c478bd9Sstevel@tonic-gate #undef lock 27447c478bd9Sstevel@tonic-gate #undef msec 27457c478bd9Sstevel@tonic-gate #define RTA_IGN \ 27467c478bd9Sstevel@tonic-gate (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC) 27477c478bd9Sstevel@tonic-gate if (verbose) { 274845916cd2Sjpk pmsg_common(rtm, msglen); 274945916cd2Sjpk } else { 275045916cd2Sjpk const char *sptr, *endptr; 275145916cd2Sjpk const struct sockaddr *sa; 275245916cd2Sjpk uint_t addrs; 275345916cd2Sjpk 275445916cd2Sjpk /* Not verbose; just print out the exceptional cases */ 275545916cd2Sjpk if (rtm->rtm_addrs &~ RTA_IGN) { 275645916cd2Sjpk (void) printf("\nsockaddrs: "); 27577c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_addrs, addrnames); 275845916cd2Sjpk } 275945916cd2Sjpk sptr = (const char *)(rtm + 1); 276045916cd2Sjpk endptr = (const char *)rtm + msglen; 276145916cd2Sjpk addrs = rtm->rtm_addrs; 276245916cd2Sjpk while (addrs != 0 && sptr + sizeof (*sa) <= endptr) { 276345916cd2Sjpk addrs &= addrs - 1; 276445916cd2Sjpk /* LINTED */ 276545916cd2Sjpk sa = (const struct sockaddr *)sptr; 276645916cd2Sjpk ADVANCE(sptr, sa); 276745916cd2Sjpk } 276845916cd2Sjpk if (addrs == 0) 276945916cd2Sjpk pmsg_secattr(sptr, endptr - sptr, " secattr: "); 27707c478bd9Sstevel@tonic-gate (void) putchar('\n'); 27717c478bd9Sstevel@tonic-gate } 27727c478bd9Sstevel@tonic-gate #undef RTA_IGN 27737c478bd9Sstevel@tonic-gate } 27747c478bd9Sstevel@tonic-gate 277545916cd2Sjpk static void 277645916cd2Sjpk pmsg_common(const struct rt_msghdr *rtm, size_t msglen) 27777c478bd9Sstevel@tonic-gate { 27787c478bd9Sstevel@tonic-gate (void) printf("\nlocks: "); 27797c478bd9Sstevel@tonic-gate bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames); 27807c478bd9Sstevel@tonic-gate (void) printf(" inits: "); 27817c478bd9Sstevel@tonic-gate bprintf(stdout, (int)rtm->rtm_inits, metricnames); 278245916cd2Sjpk pmsg_addrs((const char *)(rtm + 1), msglen - sizeof (*rtm), 278345916cd2Sjpk rtm->rtm_addrs); 27847c478bd9Sstevel@tonic-gate } 27857c478bd9Sstevel@tonic-gate 278645916cd2Sjpk static void 278745916cd2Sjpk pmsg_addrs(const char *cp, size_t msglen, uint_t addrs) 27887c478bd9Sstevel@tonic-gate { 278945916cd2Sjpk const struct sockaddr *sa; 279045916cd2Sjpk const char *maxptr; 27917c478bd9Sstevel@tonic-gate int i; 27927c478bd9Sstevel@tonic-gate 279345916cd2Sjpk if (addrs != 0) { 27947c478bd9Sstevel@tonic-gate (void) printf("\nsockaddrs: "); 27957c478bd9Sstevel@tonic-gate bprintf(stdout, addrs, addrnames); 27967c478bd9Sstevel@tonic-gate (void) putchar('\n'); 279745916cd2Sjpk maxptr = cp + msglen; 279845916cd2Sjpk for (i = 1; i != 0 && cp + sizeof (*sa) <= maxptr; i <<= 1) { 27997c478bd9Sstevel@tonic-gate if (i & addrs) { 28007c478bd9Sstevel@tonic-gate /* LINTED */ 280145916cd2Sjpk sa = (const struct sockaddr *)cp; 28027c478bd9Sstevel@tonic-gate (void) printf(" %s", routename(sa)); 28037c478bd9Sstevel@tonic-gate ADVANCE(cp, sa); 28047c478bd9Sstevel@tonic-gate } 28057c478bd9Sstevel@tonic-gate } 280645916cd2Sjpk if (i != 0) 280745916cd2Sjpk msglen = 0; 280845916cd2Sjpk else 280945916cd2Sjpk msglen = maxptr - cp; 281045916cd2Sjpk } 281145916cd2Sjpk pmsg_secattr(cp, msglen, "secattr: "); 28127c478bd9Sstevel@tonic-gate (void) putchar('\n'); 28137c478bd9Sstevel@tonic-gate (void) fflush(stdout); 28147c478bd9Sstevel@tonic-gate } 28157c478bd9Sstevel@tonic-gate 28167c478bd9Sstevel@tonic-gate void 28177c478bd9Sstevel@tonic-gate bprintf(FILE *fp, int b, char *s) 28187c478bd9Sstevel@tonic-gate { 28197c478bd9Sstevel@tonic-gate int i; 28207c478bd9Sstevel@tonic-gate boolean_t gotsome = B_FALSE; 28217c478bd9Sstevel@tonic-gate 28227c478bd9Sstevel@tonic-gate if (b == 0) 28237c478bd9Sstevel@tonic-gate return; 28247c478bd9Sstevel@tonic-gate while ((i = *s++) != 0) { 28257c478bd9Sstevel@tonic-gate if (b & (1 << (i - 1))) { 28267c478bd9Sstevel@tonic-gate if (!gotsome) 28277c478bd9Sstevel@tonic-gate i = '<'; 28287c478bd9Sstevel@tonic-gate else 28297c478bd9Sstevel@tonic-gate i = ','; 28307c478bd9Sstevel@tonic-gate (void) putc(i, fp); 28317c478bd9Sstevel@tonic-gate gotsome = B_TRUE; 28327c478bd9Sstevel@tonic-gate for (; (i = *s) > ' '; s++) 28337c478bd9Sstevel@tonic-gate (void) putc(i, fp); 28347c478bd9Sstevel@tonic-gate } else { 28357c478bd9Sstevel@tonic-gate while (*s > ' ') 28367c478bd9Sstevel@tonic-gate s++; 28377c478bd9Sstevel@tonic-gate } 28387c478bd9Sstevel@tonic-gate } 28397c478bd9Sstevel@tonic-gate if (gotsome) 28407c478bd9Sstevel@tonic-gate (void) putc('>', fp); 28417c478bd9Sstevel@tonic-gate } 28427c478bd9Sstevel@tonic-gate 28437c478bd9Sstevel@tonic-gate int 2844a59fa508Sjl138328 keyword(const char *cp) 28457c478bd9Sstevel@tonic-gate { 28467c478bd9Sstevel@tonic-gate struct keytab *kt = keywords; 28477c478bd9Sstevel@tonic-gate 28487c478bd9Sstevel@tonic-gate while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 28497c478bd9Sstevel@tonic-gate kt++; 28507c478bd9Sstevel@tonic-gate return (kt->kt_i); 28517c478bd9Sstevel@tonic-gate } 28527c478bd9Sstevel@tonic-gate 28537c478bd9Sstevel@tonic-gate void 2854a59fa508Sjl138328 sodump(su_t *su, char *which) 28557c478bd9Sstevel@tonic-gate { 28567c478bd9Sstevel@tonic-gate static char obuf[INET6_ADDRSTRLEN]; 28577c478bd9Sstevel@tonic-gate 28587c478bd9Sstevel@tonic-gate switch (su->sa.sa_family) { 28597c478bd9Sstevel@tonic-gate case AF_LINK: 28607c478bd9Sstevel@tonic-gate (void) printf("%s: link %s; ", 28617c478bd9Sstevel@tonic-gate which, link_ntoa(&su->sdl)); 28627c478bd9Sstevel@tonic-gate break; 28637c478bd9Sstevel@tonic-gate case AF_INET: 28647c478bd9Sstevel@tonic-gate (void) printf("%s: inet %s; ", 28657c478bd9Sstevel@tonic-gate which, inet_ntoa(su->sin.sin_addr)); 28667c478bd9Sstevel@tonic-gate break; 28677c478bd9Sstevel@tonic-gate case AF_INET6: 28687c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, (void *)&su->sin6.sin6_addr, obuf, 28697c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN) != NULL) { 28707c478bd9Sstevel@tonic-gate (void) printf("%s: inet6 %s; ", which, obuf); 28717c478bd9Sstevel@tonic-gate break; 28727c478bd9Sstevel@tonic-gate } 28737c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 28747c478bd9Sstevel@tonic-gate default: 28757c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 28767c478bd9Sstevel@tonic-gate /* NOTREACHED */ 28777c478bd9Sstevel@tonic-gate } 28787c478bd9Sstevel@tonic-gate (void) fflush(stdout); 28797c478bd9Sstevel@tonic-gate } 28807c478bd9Sstevel@tonic-gate 28817c478bd9Sstevel@tonic-gate /* States */ 28827c478bd9Sstevel@tonic-gate #define VIRGIN 0 28837c478bd9Sstevel@tonic-gate #define GOTONE 1 28847c478bd9Sstevel@tonic-gate #define GOTTWO 2 28857c478bd9Sstevel@tonic-gate #define RESET 3 28867c478bd9Sstevel@tonic-gate /* Inputs */ 28877c478bd9Sstevel@tonic-gate #define DIGIT (4*0) 28887c478bd9Sstevel@tonic-gate #define END (4*1) 28897c478bd9Sstevel@tonic-gate #define DELIM (4*2) 28907c478bd9Sstevel@tonic-gate #define LETTER (4*3) 28917c478bd9Sstevel@tonic-gate 28927c478bd9Sstevel@tonic-gate void 28937c478bd9Sstevel@tonic-gate sockaddr(char *addr, struct sockaddr *sa) 28947c478bd9Sstevel@tonic-gate { 28957c478bd9Sstevel@tonic-gate char *cp = (char *)sa; 28967c478bd9Sstevel@tonic-gate int size = salen(sa); 28977c478bd9Sstevel@tonic-gate char *cplim = cp + size; 28987c478bd9Sstevel@tonic-gate int byte = 0, state = VIRGIN, new; 28997c478bd9Sstevel@tonic-gate 29007c478bd9Sstevel@tonic-gate (void) memset(cp, 0, size); 29017c478bd9Sstevel@tonic-gate cp++; 29027c478bd9Sstevel@tonic-gate do { 29037c478bd9Sstevel@tonic-gate if ((*addr >= '0') && (*addr <= '9')) { 29047c478bd9Sstevel@tonic-gate new = *addr - '0'; 29057c478bd9Sstevel@tonic-gate } else if ((*addr >= 'a') && (*addr <= 'f')) { 29067c478bd9Sstevel@tonic-gate new = *addr - 'a' + 10; 29077c478bd9Sstevel@tonic-gate } else if ((*addr >= 'A') && (*addr <= 'F')) { 29087c478bd9Sstevel@tonic-gate new = *addr - 'A' + 10; 29097c478bd9Sstevel@tonic-gate } else if (*addr == 0) { 29107c478bd9Sstevel@tonic-gate state |= END; 29117c478bd9Sstevel@tonic-gate } else { 29127c478bd9Sstevel@tonic-gate state |= DELIM; 29137c478bd9Sstevel@tonic-gate } 29147c478bd9Sstevel@tonic-gate addr++; 29157c478bd9Sstevel@tonic-gate switch (state /* | INPUT */) { 29167c478bd9Sstevel@tonic-gate case GOTTWO | DIGIT: 29177c478bd9Sstevel@tonic-gate *cp++ = byte; 29187c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 29197c478bd9Sstevel@tonic-gate case VIRGIN | DIGIT: 29207c478bd9Sstevel@tonic-gate state = GOTONE; byte = new; continue; 29217c478bd9Sstevel@tonic-gate case GOTONE | DIGIT: 29227c478bd9Sstevel@tonic-gate state = GOTTWO; byte = new + (byte << 4); continue; 29237c478bd9Sstevel@tonic-gate default: /* | DELIM */ 29247c478bd9Sstevel@tonic-gate state = VIRGIN; *cp++ = byte; byte = 0; continue; 29257c478bd9Sstevel@tonic-gate case GOTONE | END: 29267c478bd9Sstevel@tonic-gate case GOTTWO | END: 29277c478bd9Sstevel@tonic-gate *cp++ = byte; 29287c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 29297c478bd9Sstevel@tonic-gate case VIRGIN | END: 29307c478bd9Sstevel@tonic-gate break; 29317c478bd9Sstevel@tonic-gate } 29327c478bd9Sstevel@tonic-gate break; 29337c478bd9Sstevel@tonic-gate } while (cp < cplim); 29347c478bd9Sstevel@tonic-gate } 29357c478bd9Sstevel@tonic-gate 29367c478bd9Sstevel@tonic-gate int 293745916cd2Sjpk salen(const struct sockaddr *sa) 29387c478bd9Sstevel@tonic-gate { 29397c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 29407c478bd9Sstevel@tonic-gate case AF_INET: 29417c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_in)); 29427c478bd9Sstevel@tonic-gate case AF_LINK: 29437c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_dl)); 29447c478bd9Sstevel@tonic-gate case AF_INET6: 29457c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_in6)); 29467c478bd9Sstevel@tonic-gate default: 29477c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr)); 29487c478bd9Sstevel@tonic-gate } 29497c478bd9Sstevel@tonic-gate } 29507c478bd9Sstevel@tonic-gate 29517c478bd9Sstevel@tonic-gate void 29527c478bd9Sstevel@tonic-gate link_addr(const char *addr, struct sockaddr_dl *sdl) 29537c478bd9Sstevel@tonic-gate { 29547c478bd9Sstevel@tonic-gate char *cp = sdl->sdl_data; 29557c478bd9Sstevel@tonic-gate char *cplim = sizeof (struct sockaddr_dl) + (char *)sdl; 29567c478bd9Sstevel@tonic-gate int byte = 0, state = VIRGIN, new; 29577c478bd9Sstevel@tonic-gate 29587c478bd9Sstevel@tonic-gate (void) memset(sdl, 0, sizeof (struct sockaddr_dl)); 29597c478bd9Sstevel@tonic-gate sdl->sdl_family = AF_LINK; 29607c478bd9Sstevel@tonic-gate do { 29617c478bd9Sstevel@tonic-gate state &= ~LETTER; 29627c478bd9Sstevel@tonic-gate if ((*addr >= '0') && (*addr <= '9')) { 29637c478bd9Sstevel@tonic-gate new = *addr - '0'; 29647c478bd9Sstevel@tonic-gate } else if ((*addr >= 'a') && (*addr <= 'f')) { 29657c478bd9Sstevel@tonic-gate new = *addr - 'a' + 10; 29667c478bd9Sstevel@tonic-gate } else if ((*addr >= 'A') && (*addr <= 'F')) { 29677c478bd9Sstevel@tonic-gate new = *addr - 'A' + 10; 29687c478bd9Sstevel@tonic-gate } else if (*addr == 0) { 29697c478bd9Sstevel@tonic-gate state |= END; 29707c478bd9Sstevel@tonic-gate } else if (state == VIRGIN && 29717c478bd9Sstevel@tonic-gate (((*addr >= 'A') && (*addr <= 'Z')) || 29727c478bd9Sstevel@tonic-gate ((*addr >= 'a') && (*addr <= 'z')))) { 29737c478bd9Sstevel@tonic-gate state |= LETTER; 29747c478bd9Sstevel@tonic-gate } else { 29757c478bd9Sstevel@tonic-gate state |= DELIM; 29767c478bd9Sstevel@tonic-gate } 29777c478bd9Sstevel@tonic-gate addr++; 29787c478bd9Sstevel@tonic-gate switch (state /* | INPUT */) { 29797c478bd9Sstevel@tonic-gate case VIRGIN | DIGIT: 29807c478bd9Sstevel@tonic-gate case VIRGIN | LETTER: 29817c478bd9Sstevel@tonic-gate *cp++ = addr[-1]; 29827c478bd9Sstevel@tonic-gate continue; 29837c478bd9Sstevel@tonic-gate case VIRGIN | DELIM: 29847c478bd9Sstevel@tonic-gate state = RESET; 29857c478bd9Sstevel@tonic-gate sdl->sdl_nlen = cp - sdl->sdl_data; 29867c478bd9Sstevel@tonic-gate continue; 29877c478bd9Sstevel@tonic-gate case GOTTWO | DIGIT: 29887c478bd9Sstevel@tonic-gate *cp++ = byte; 29897c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 29907c478bd9Sstevel@tonic-gate case RESET | DIGIT: 29917c478bd9Sstevel@tonic-gate state = GOTONE; 29927c478bd9Sstevel@tonic-gate byte = new; 29937c478bd9Sstevel@tonic-gate continue; 29947c478bd9Sstevel@tonic-gate case GOTONE | DIGIT: 29957c478bd9Sstevel@tonic-gate state = GOTTWO; 29967c478bd9Sstevel@tonic-gate byte = new + (byte << 4); 29977c478bd9Sstevel@tonic-gate continue; 29987c478bd9Sstevel@tonic-gate default: /* | DELIM */ 29997c478bd9Sstevel@tonic-gate state = RESET; 30007c478bd9Sstevel@tonic-gate *cp++ = byte; 30017c478bd9Sstevel@tonic-gate byte = 0; 30027c478bd9Sstevel@tonic-gate continue; 30037c478bd9Sstevel@tonic-gate case GOTONE | END: 30047c478bd9Sstevel@tonic-gate case GOTTWO | END: 30057c478bd9Sstevel@tonic-gate *cp++ = byte; 30067c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 30077c478bd9Sstevel@tonic-gate case RESET | END: 30087c478bd9Sstevel@tonic-gate break; 30097c478bd9Sstevel@tonic-gate } 30107c478bd9Sstevel@tonic-gate break; 30117c478bd9Sstevel@tonic-gate } while (cp < cplim); 30127c478bd9Sstevel@tonic-gate sdl->sdl_alen = cp - LLADDR(sdl); 30137c478bd9Sstevel@tonic-gate } 30147c478bd9Sstevel@tonic-gate 30157c478bd9Sstevel@tonic-gate static char hexlist[] = "0123456789abcdef"; 30167c478bd9Sstevel@tonic-gate 30177c478bd9Sstevel@tonic-gate char * 30187c478bd9Sstevel@tonic-gate link_ntoa(const struct sockaddr_dl *sdl) 30197c478bd9Sstevel@tonic-gate { 30207c478bd9Sstevel@tonic-gate static char obuf[64]; 30217c478bd9Sstevel@tonic-gate char *out = obuf; 30227c478bd9Sstevel@tonic-gate int i; 30237c478bd9Sstevel@tonic-gate uchar_t *in = (uchar_t *)LLADDR(sdl); 30247c478bd9Sstevel@tonic-gate uchar_t *inlim = in + sdl->sdl_alen; 30257c478bd9Sstevel@tonic-gate boolean_t firsttime = B_TRUE; 30267c478bd9Sstevel@tonic-gate 30277c478bd9Sstevel@tonic-gate if (sdl->sdl_nlen) { 30287c478bd9Sstevel@tonic-gate (void) memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen); 30297c478bd9Sstevel@tonic-gate out += sdl->sdl_nlen; 30307c478bd9Sstevel@tonic-gate if (sdl->sdl_alen) 30317c478bd9Sstevel@tonic-gate *out++ = ':'; 30327c478bd9Sstevel@tonic-gate } 30337c478bd9Sstevel@tonic-gate while (in < inlim) { 30347c478bd9Sstevel@tonic-gate if (firsttime) 30357c478bd9Sstevel@tonic-gate firsttime = B_FALSE; 30367c478bd9Sstevel@tonic-gate else 30377c478bd9Sstevel@tonic-gate *out++ = '.'; 30387c478bd9Sstevel@tonic-gate i = *in++; 30397c478bd9Sstevel@tonic-gate if (i > 0xf) { 30407c478bd9Sstevel@tonic-gate out[1] = hexlist[i & 0xf]; 30417c478bd9Sstevel@tonic-gate i >>= 4; 30427c478bd9Sstevel@tonic-gate out[0] = hexlist[i]; 30437c478bd9Sstevel@tonic-gate out += 2; 30447c478bd9Sstevel@tonic-gate } else { 30457c478bd9Sstevel@tonic-gate *out++ = hexlist[i]; 30467c478bd9Sstevel@tonic-gate } 30477c478bd9Sstevel@tonic-gate } 30487c478bd9Sstevel@tonic-gate *out = 0; 30497c478bd9Sstevel@tonic-gate return (obuf); 30507c478bd9Sstevel@tonic-gate } 30517c478bd9Sstevel@tonic-gate 30527c478bd9Sstevel@tonic-gate static mib_item_t * 30537c478bd9Sstevel@tonic-gate mibget(int sd) 30547c478bd9Sstevel@tonic-gate { 30557c478bd9Sstevel@tonic-gate intmax_t buf[512 / sizeof (intmax_t)]; 30567c478bd9Sstevel@tonic-gate int flags; 30577c478bd9Sstevel@tonic-gate int i, j, getcode; 30587c478bd9Sstevel@tonic-gate struct strbuf ctlbuf, databuf; 30597c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; 30607c478bd9Sstevel@tonic-gate struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; 30617c478bd9Sstevel@tonic-gate struct T_error_ack *tea = (struct T_error_ack *)buf; 30627c478bd9Sstevel@tonic-gate struct opthdr *req; 30637c478bd9Sstevel@tonic-gate mib_item_t *first_item = NULL; 30647c478bd9Sstevel@tonic-gate mib_item_t *last_item = NULL; 30657c478bd9Sstevel@tonic-gate mib_item_t *temp; 30667c478bd9Sstevel@tonic-gate 30677c478bd9Sstevel@tonic-gate tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 30687c478bd9Sstevel@tonic-gate tor->OPT_offset = sizeof (struct T_optmgmt_req); 30697c478bd9Sstevel@tonic-gate tor->OPT_length = sizeof (struct opthdr); 30707c478bd9Sstevel@tonic-gate tor->MGMT_flags = T_CURRENT; 30717c478bd9Sstevel@tonic-gate req = (struct opthdr *)&tor[1]; 30727c478bd9Sstevel@tonic-gate req->level = MIB2_IP; /* any MIB2_xxx value ok here */ 30737c478bd9Sstevel@tonic-gate req->name = 0; 30747c478bd9Sstevel@tonic-gate req->len = 0; 30757c478bd9Sstevel@tonic-gate 30767c478bd9Sstevel@tonic-gate ctlbuf.buf = (char *)buf; 30777c478bd9Sstevel@tonic-gate ctlbuf.len = tor->OPT_length + tor->OPT_offset; 30787c478bd9Sstevel@tonic-gate flags = 0; 30797c478bd9Sstevel@tonic-gate if (putmsg(sd, &ctlbuf, NULL, flags) < 0) { 30807c478bd9Sstevel@tonic-gate perror("mibget: putmsg (ctl)"); 30817c478bd9Sstevel@tonic-gate return (NULL); 30827c478bd9Sstevel@tonic-gate } 30837c478bd9Sstevel@tonic-gate /* 30847c478bd9Sstevel@tonic-gate * each reply consists of a ctl part for one fixed structure 30857c478bd9Sstevel@tonic-gate * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK, 30867c478bd9Sstevel@tonic-gate * containing an opthdr structure. level/name identify the entry, 30877c478bd9Sstevel@tonic-gate * len is the size of the data part of the message. 30887c478bd9Sstevel@tonic-gate */ 30897c478bd9Sstevel@tonic-gate req = (struct opthdr *)&toa[1]; 30907c478bd9Sstevel@tonic-gate ctlbuf.maxlen = sizeof (buf); 30917c478bd9Sstevel@tonic-gate for (j = 1; ; j++) { 30927c478bd9Sstevel@tonic-gate flags = 0; 30937c478bd9Sstevel@tonic-gate getcode = getmsg(sd, &ctlbuf, NULL, &flags); 30947c478bd9Sstevel@tonic-gate if (getcode < 0) { 30957c478bd9Sstevel@tonic-gate perror("mibget: getmsg (ctl)"); 30967c478bd9Sstevel@tonic-gate if (verbose) { 30977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 30987c478bd9Sstevel@tonic-gate "# level name len\n"); 30997c478bd9Sstevel@tonic-gate i = 0; 31007c478bd9Sstevel@tonic-gate for (last_item = first_item; last_item != NULL; 31017c478bd9Sstevel@tonic-gate last_item = last_item->next_item) { 31027c478bd9Sstevel@tonic-gate (void) printf("%d %4ld %5ld %ld\n", 31037c478bd9Sstevel@tonic-gate ++i, last_item->group, 31047c478bd9Sstevel@tonic-gate last_item->mib_id, 31057c478bd9Sstevel@tonic-gate last_item->length); 31067c478bd9Sstevel@tonic-gate } 31077c478bd9Sstevel@tonic-gate } 31087c478bd9Sstevel@tonic-gate break; 31097c478bd9Sstevel@tonic-gate } 31107c478bd9Sstevel@tonic-gate if (getcode == 0 && 31117c478bd9Sstevel@tonic-gate ctlbuf.len >= sizeof (struct T_optmgmt_ack) && 31127c478bd9Sstevel@tonic-gate toa->PRIM_type == T_OPTMGMT_ACK && 31137c478bd9Sstevel@tonic-gate toa->MGMT_flags == T_SUCCESS && 31147c478bd9Sstevel@tonic-gate req->len == 0) { 31157c478bd9Sstevel@tonic-gate if (verbose) { 31167c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg() %d returned EOD " 31177c478bd9Sstevel@tonic-gate "(level %lu, name %lu)\n", j, req->level, 31187c478bd9Sstevel@tonic-gate req->name); 31197c478bd9Sstevel@tonic-gate } 31207c478bd9Sstevel@tonic-gate return (first_item); /* this is EOD msg */ 31217c478bd9Sstevel@tonic-gate } 31227c478bd9Sstevel@tonic-gate 31237c478bd9Sstevel@tonic-gate if (ctlbuf.len >= sizeof (struct T_error_ack) && 31247c478bd9Sstevel@tonic-gate tea->PRIM_type == T_ERROR_ACK) { 31257c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("mibget %d gives " 31267c478bd9Sstevel@tonic-gate "T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = " 31277c478bd9Sstevel@tonic-gate "0x%lx\n"), j, tea->TLI_error, tea->UNIX_error); 3128*bd670b35SErik Nordmark errno = (tea->TLI_error == TSYSERR) ? 3129*bd670b35SErik Nordmark tea->UNIX_error : EPROTO; 31307c478bd9Sstevel@tonic-gate break; 31317c478bd9Sstevel@tonic-gate } 31327c478bd9Sstevel@tonic-gate 31337c478bd9Sstevel@tonic-gate if (getcode != MOREDATA || 31347c478bd9Sstevel@tonic-gate ctlbuf.len < sizeof (struct T_optmgmt_ack) || 31357c478bd9Sstevel@tonic-gate toa->PRIM_type != T_OPTMGMT_ACK || 31367c478bd9Sstevel@tonic-gate toa->MGMT_flags != T_SUCCESS) { 31377c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg(ctl) %d returned %d, " 31387c478bd9Sstevel@tonic-gate "ctlbuf.len = %d, PRIM_type = %ld\n", 31397c478bd9Sstevel@tonic-gate j, getcode, ctlbuf.len, toa->PRIM_type); 31407c478bd9Sstevel@tonic-gate if (toa->PRIM_type == T_OPTMGMT_ACK) { 31417c478bd9Sstevel@tonic-gate (void) printf("T_OPTMGMT_ACK: " 31427c478bd9Sstevel@tonic-gate "MGMT_flags = 0x%lx, req->len = %ld\n", 31437c478bd9Sstevel@tonic-gate toa->MGMT_flags, req->len); 31447c478bd9Sstevel@tonic-gate } 31457c478bd9Sstevel@tonic-gate errno = ENOMSG; 31467c478bd9Sstevel@tonic-gate break; 31477c478bd9Sstevel@tonic-gate } 31487c478bd9Sstevel@tonic-gate 31497c478bd9Sstevel@tonic-gate temp = malloc(sizeof (mib_item_t)); 31507c478bd9Sstevel@tonic-gate if (temp == NULL) { 31517c478bd9Sstevel@tonic-gate perror("mibget: malloc"); 31527c478bd9Sstevel@tonic-gate break; 31537c478bd9Sstevel@tonic-gate } 31547c478bd9Sstevel@tonic-gate if (last_item != NULL) 31557c478bd9Sstevel@tonic-gate last_item->next_item = temp; 31567c478bd9Sstevel@tonic-gate else 31577c478bd9Sstevel@tonic-gate first_item = temp; 31587c478bd9Sstevel@tonic-gate last_item = temp; 31597c478bd9Sstevel@tonic-gate last_item->next_item = NULL; 31607c478bd9Sstevel@tonic-gate last_item->group = req->level; 31617c478bd9Sstevel@tonic-gate last_item->mib_id = req->name; 31627c478bd9Sstevel@tonic-gate last_item->length = req->len; 31637c478bd9Sstevel@tonic-gate last_item->valp = malloc(req->len); 31647c478bd9Sstevel@tonic-gate if (verbose) { 31657c478bd9Sstevel@tonic-gate (void) printf("msg %d: group = %4ld mib_id = %5ld " 31667c478bd9Sstevel@tonic-gate "length = %ld\n", 31677c478bd9Sstevel@tonic-gate j, last_item->group, last_item->mib_id, 31687c478bd9Sstevel@tonic-gate last_item->length); 31697c478bd9Sstevel@tonic-gate } 31707c478bd9Sstevel@tonic-gate 31717c478bd9Sstevel@tonic-gate databuf.maxlen = last_item->length; 31727c478bd9Sstevel@tonic-gate databuf.buf = (char *)last_item->valp; 31737c478bd9Sstevel@tonic-gate databuf.len = 0; 31747c478bd9Sstevel@tonic-gate flags = 0; 31757c478bd9Sstevel@tonic-gate getcode = getmsg(sd, NULL, &databuf, &flags); 31767c478bd9Sstevel@tonic-gate if (getcode < 0) { 31777c478bd9Sstevel@tonic-gate perror("mibget: getmsg (data)"); 31787c478bd9Sstevel@tonic-gate break; 31797c478bd9Sstevel@tonic-gate } else if (getcode != 0) { 31807c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg(data) returned %d, " 31817c478bd9Sstevel@tonic-gate "databuf.maxlen = %d, databuf.len = %d\n", 31827c478bd9Sstevel@tonic-gate getcode, databuf.maxlen, databuf.len); 31837c478bd9Sstevel@tonic-gate break; 31847c478bd9Sstevel@tonic-gate } 31857c478bd9Sstevel@tonic-gate } 31867c478bd9Sstevel@tonic-gate 31877c478bd9Sstevel@tonic-gate /* 31887c478bd9Sstevel@tonic-gate * On error, free all the allocated mib_item_t objects. 31897c478bd9Sstevel@tonic-gate */ 31907c478bd9Sstevel@tonic-gate while (first_item != NULL) { 31917c478bd9Sstevel@tonic-gate last_item = first_item; 31927c478bd9Sstevel@tonic-gate first_item = first_item->next_item; 31937c478bd9Sstevel@tonic-gate free(last_item); 31947c478bd9Sstevel@tonic-gate } 31957c478bd9Sstevel@tonic-gate return (NULL); 31967c478bd9Sstevel@tonic-gate } 319745916cd2Sjpk 319845916cd2Sjpk /* 319945916cd2Sjpk * print label security attributes for gateways. 320045916cd2Sjpk */ 320145916cd2Sjpk static void 320245916cd2Sjpk pmsg_secattr(const char *sptr, size_t msglen, const char *labelstr) 320345916cd2Sjpk { 320445916cd2Sjpk rtm_ext_t rtm_ext; 320545916cd2Sjpk tsol_rtsecattr_t sp; 320645916cd2Sjpk struct rtsa_s *rtsa = &sp.rtsa_attr[0]; 320745916cd2Sjpk const char *endptr; 320845916cd2Sjpk char buf[256]; 320945916cd2Sjpk int i; 321045916cd2Sjpk 321145916cd2Sjpk if (!is_system_labeled()) 321245916cd2Sjpk return; 321345916cd2Sjpk 321445916cd2Sjpk endptr = sptr + msglen; 321545916cd2Sjpk 321645916cd2Sjpk for (;;) { 321745916cd2Sjpk if (sptr + sizeof (rtm_ext_t) + sizeof (sp) > endptr) 321845916cd2Sjpk return; 321945916cd2Sjpk 322045916cd2Sjpk bcopy(sptr, &rtm_ext, sizeof (rtm_ext)); 322145916cd2Sjpk sptr += sizeof (rtm_ext); 322245916cd2Sjpk if (rtm_ext.rtmex_type == RTMEX_GATEWAY_SECATTR) 322345916cd2Sjpk break; 322445916cd2Sjpk sptr += rtm_ext.rtmex_len; 322545916cd2Sjpk } 322645916cd2Sjpk 322745916cd2Sjpk /* bail if this entry is corrupt or overruns buffer length */ 322845916cd2Sjpk if (rtm_ext.rtmex_len < sizeof (sp) || 322945916cd2Sjpk sptr + rtm_ext.rtmex_len > endptr) 323045916cd2Sjpk return; 323145916cd2Sjpk 323245916cd2Sjpk /* run up just to the end of this extension */ 323345916cd2Sjpk endptr = sptr + rtm_ext.rtmex_len; 323445916cd2Sjpk 323545916cd2Sjpk bcopy(sptr, &sp, sizeof (sp)); 323645916cd2Sjpk sptr += sizeof (sp); 323745916cd2Sjpk 323845916cd2Sjpk if (sptr + (sp.rtsa_cnt - 1) * sizeof (*rtsa) != endptr) 323945916cd2Sjpk return; 324045916cd2Sjpk 324145916cd2Sjpk for (i = 0; i < sp.rtsa_cnt; i++) { 324245916cd2Sjpk if (i > 0) { 324345916cd2Sjpk /* first element is part of sp initalized above */ 324445916cd2Sjpk bcopy(sptr, rtsa, sizeof (*rtsa)); 324545916cd2Sjpk sptr += sizeof (*rtsa); 324645916cd2Sjpk } 324745916cd2Sjpk (void) printf("\n%s%s", labelstr, rtsa_to_str(rtsa, buf, 324845916cd2Sjpk sizeof (buf))); 324945916cd2Sjpk } 325045916cd2Sjpk } 3251