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