1 0 stevel /* 2 11042 Erik * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 0 stevel * Use is subject to license terms. 4 0 stevel */ 5 0 stevel 6 0 stevel /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 7 1291 jl138328 /* All Rights Reserved */ 8 0 stevel 9 0 stevel /* Copyright (c) 1990 Mentat Inc. */ 10 0 stevel 11 0 stevel /* 12 0 stevel * 13 0 stevel * Copyright (c) 1983, 1989, 1991, 1993 14 0 stevel * The Regents of the University of California. All rights reserved. 15 0 stevel * 16 0 stevel * Redistribution and use in source and binary forms, with or without 17 0 stevel * modification, are permitted provided that the following conditions 18 0 stevel * are met: 19 0 stevel * 1. Redistributions of source code must retain the above copyright 20 0 stevel * notice, this list of conditions and the following disclaimer. 21 0 stevel * 2. Redistributions in binary form must reproduce the above copyright 22 0 stevel * notice, this list of conditions and the following disclaimer in the 23 0 stevel * documentation and/or other materials provided with the distribution. 24 0 stevel * 3. All advertising materials mentioning features or use of this software 25 0 stevel * must display the following acknowledgement: 26 0 stevel * This product includes software developed by the University of 27 0 stevel * California, Berkeley and its contributors. 28 0 stevel * 4. Neither the name of the University nor the names of its contributors 29 0 stevel * may be used to endorse or promote products derived from this software 30 0 stevel * without specific prior written permission. 31 0 stevel * 32 0 stevel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33 0 stevel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 0 stevel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 0 stevel * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36 0 stevel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 0 stevel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 0 stevel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 0 stevel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 0 stevel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 0 stevel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 0 stevel * SUCH DAMAGE. 43 0 stevel * 44 0 stevel * @(#)route.c 8.6 (Berkeley) 4/28/95 45 0 stevel * @(#)linkaddr.c 8.1 (Berkeley) 6/4/93 46 0 stevel */ 47 0 stevel 48 0 stevel #include <sys/param.h> 49 0 stevel #include <sys/file.h> 50 0 stevel #include <sys/socket.h> 51 0 stevel #include <sys/ioctl.h> 52 1291 jl138328 #include <sys/stat.h> 53 0 stevel #include <sys/stream.h> 54 1291 jl138328 #include <sys/sysmacros.h> 55 156 dduvall #include <sys/tihdr.h> 56 1291 jl138328 #include <sys/types.h> 57 192 carlsonj #include <sys/ccompile.h> 58 0 stevel 59 0 stevel #include <net/if.h> 60 0 stevel #include <net/route.h> 61 0 stevel #include <net/if_dl.h> 62 0 stevel #include <netinet/in.h> 63 0 stevel #include <arpa/inet.h> 64 0 stevel #include <netdb.h> 65 0 stevel #include <inet/mib2.h> 66 0 stevel #include <inet/ip.h> 67 0 stevel 68 1291 jl138328 #include <limits.h> 69 0 stevel #include <locale.h> 70 0 stevel 71 0 stevel #include <errno.h> 72 0 stevel #include <unistd.h> 73 0 stevel #include <stdio.h> 74 0 stevel #include <stdlib.h> 75 1676 jpk #include <stddef.h> 76 0 stevel #include <string.h> 77 0 stevel #include <stropts.h> 78 0 stevel #include <fcntl.h> 79 1291 jl138328 #include <stdarg.h> 80 0 stevel #include <assert.h> 81 1676 jpk #include <strings.h> 82 1676 jpk 83 1676 jpk #include <libtsnet.h> 84 1676 jpk #include <tsol/label.h> 85 0 stevel 86 0 stevel static struct keytab { 87 0 stevel char *kt_cp; 88 0 stevel int kt_i; 89 0 stevel } keywords[] = { 90 0 stevel #define K_ADD 1 91 0 stevel {"add", K_ADD}, 92 0 stevel #define K_BLACKHOLE 2 93 0 stevel {"blackhole", K_BLACKHOLE}, 94 0 stevel #define K_CHANGE 3 95 0 stevel {"change", K_CHANGE}, 96 0 stevel #define K_CLONING 4 97 0 stevel {"cloning", K_CLONING}, 98 0 stevel #define K_DELETE 5 99 0 stevel {"delete", K_DELETE}, 100 0 stevel #define K_DST 6 101 0 stevel {"dst", K_DST}, 102 0 stevel #define K_EXPIRE 7 103 0 stevel {"expire", K_EXPIRE}, 104 0 stevel #define K_FLUSH 8 105 0 stevel {"flush", K_FLUSH}, 106 0 stevel #define K_GATEWAY 9 107 0 stevel {"gateway", K_GATEWAY}, 108 0 stevel #define K_GET 11 109 0 stevel {"get", K_GET}, 110 0 stevel #define K_HOPCOUNT 12 111 0 stevel {"hopcount", K_HOPCOUNT}, 112 0 stevel #define K_HOST 13 113 0 stevel {"host", K_HOST}, 114 0 stevel #define K_IFA 14 115 0 stevel {"ifa", K_IFA}, 116 0 stevel #define K_IFACE 15 117 0 stevel {"iface", K_IFACE}, 118 0 stevel #define K_IFP 16 119 0 stevel {"ifp", K_IFP}, 120 0 stevel #define K_INET 17 121 0 stevel {"inet", K_INET}, 122 0 stevel #define K_INET6 18 123 0 stevel {"inet6", K_INET6}, 124 0 stevel #define K_INTERFACE 19 125 0 stevel {"interface", K_INTERFACE}, 126 0 stevel #define K_LINK 20 127 0 stevel {"link", K_LINK}, 128 0 stevel #define K_LOCK 21 129 0 stevel {"lock", K_LOCK}, 130 0 stevel #define K_LOCKREST 22 131 0 stevel {"lockrest", K_LOCKREST}, 132 0 stevel #define K_MASK 23 133 0 stevel {"mask", K_MASK}, 134 0 stevel #define K_MONITOR 24 135 0 stevel {"monitor", K_MONITOR}, 136 0 stevel #define K_MTU 25 137 0 stevel {"mtu", K_MTU}, 138 0 stevel #define K_NET 26 139 0 stevel {"net", K_NET}, 140 0 stevel #define K_NETMASK 27 141 0 stevel {"netmask", K_NETMASK}, 142 0 stevel #define K_NOSTATIC 28 143 0 stevel {"nostatic", K_NOSTATIC}, 144 0 stevel #define K_PRIVATE 29 145 0 stevel {"private", K_PRIVATE}, 146 0 stevel #define K_PROTO1 30 147 0 stevel {"proto1", K_PROTO1}, 148 0 stevel #define K_PROTO2 31 149 0 stevel {"proto2", K_PROTO2}, 150 0 stevel #define K_RECVPIPE 32 151 0 stevel {"recvpipe", K_RECVPIPE}, 152 0 stevel #define K_REJECT 33 153 0 stevel {"reject", K_REJECT}, 154 0 stevel #define K_RTT 34 155 0 stevel {"rtt", K_RTT}, 156 0 stevel #define K_RTTVAR 35 157 0 stevel {"rttvar", K_RTTVAR}, 158 0 stevel #define K_SA 36 159 0 stevel {"sa", K_SA}, 160 0 stevel #define K_SENDPIPE 37 161 0 stevel {"sendpipe", K_SENDPIPE}, 162 0 stevel #define K_SSTHRESH 38 163 0 stevel {"ssthresh", K_SSTHRESH}, 164 0 stevel #define K_STATIC 39 165 0 stevel {"static", K_STATIC}, 166 0 stevel #define K_XRESOLVE 40 167 0 stevel {"xresolve", K_XRESOLVE}, 168 0 stevel #define K_MULTIRT 41 169 0 stevel {"multirt", K_MULTIRT}, 170 0 stevel #define K_SETSRC 42 171 0 stevel {"setsrc", K_SETSRC}, 172 1291 jl138328 #define K_SHOW 43 173 1291 jl138328 {"show", K_SHOW}, 174 1676 jpk #define K_SECATTR 43 175 1676 jpk {"secattr", K_SECATTR}, 176 11042 Erik #define K_INDIRECT 44 177 11042 Erik {"indirect", K_INDIRECT}, 178 0 stevel {0, 0} 179 0 stevel }; 180 0 stevel 181 1291 jl138328 /* 182 1291 jl138328 * Size of buffers used to hold command lines from the saved route file as 183 1291 jl138328 * well as error strings. 184 1291 jl138328 */ 185 1291 jl138328 #define BUF_SIZE 2048 186 1291 jl138328 187 1291 jl138328 typedef union sockunion { 188 0 stevel struct sockaddr sa; 189 0 stevel struct sockaddr_in sin; 190 0 stevel struct sockaddr_dl sdl; 191 0 stevel struct sockaddr_in6 sin6; 192 1291 jl138328 } su_t; 193 1291 jl138328 194 1291 jl138328 /* 195 1291 jl138328 * This structure represents the digested information from parsing arguments 196 1291 jl138328 * to route add, change, delete, and get. 197 1291 jl138328 * 198 1291 jl138328 */ 199 1291 jl138328 typedef struct rtcmd_irep { 200 1291 jl138328 int ri_cmd; 201 1291 jl138328 int ri_flags; 202 1291 jl138328 int ri_af; 203 1291 jl138328 ulong_t ri_inits; 204 1291 jl138328 struct rt_metrics ri_metrics; 205 1291 jl138328 int ri_addrs; 206 1291 jl138328 su_t ri_dst; 207 1291 jl138328 char *ri_dest_str; 208 1291 jl138328 su_t ri_src; 209 1291 jl138328 su_t ri_gate; 210 1291 jl138328 struct hostent *ri_gate_hp; 211 1291 jl138328 char *ri_gate_str; 212 1291 jl138328 su_t ri_mask; 213 1291 jl138328 su_t ri_ifa; 214 1291 jl138328 su_t ri_ifp; 215 1291 jl138328 char *ri_ifp_str; 216 1676 jpk int ri_rtsa_cnt; /* number of gateway security attributes */ 217 1676 jpk struct rtsa_s ri_rtsa; /* enough space for one attribute */ 218 1291 jl138328 } rtcmd_irep_t; 219 0 stevel 220 0 stevel typedef struct mib_item_s { 221 1676 jpk struct mib_item_s *next_item; 222 1676 jpk long group; 223 1676 jpk long mib_id; 224 1676 jpk long length; 225 1676 jpk intmax_t *valp; 226 0 stevel } mib_item_t; 227 0 stevel 228 1291 jl138328 typedef enum { 229 1291 jl138328 ADDR_TYPE_ANY, 230 1291 jl138328 ADDR_TYPE_HOST, 231 1291 jl138328 ADDR_TYPE_NET 232 1291 jl138328 } addr_type_t; 233 0 stevel 234 1291 jl138328 typedef enum { 235 1291 jl138328 SEARCH_MODE_NULL, 236 1291 jl138328 SEARCH_MODE_PRINT, 237 1291 jl138328 SEARCH_MODE_DEL 238 1291 jl138328 } search_mode_t; 239 1291 jl138328 240 1291 jl138328 static boolean_t args_to_rtcmd(rtcmd_irep_t *rcip, char **argv, 241 1291 jl138328 char *cmd_string); 242 0 stevel static void bprintf(FILE *fp, int b, char *s); 243 1291 jl138328 static boolean_t compare_rtcmd(rtcmd_irep_t *srch_rt, 244 1291 jl138328 rtcmd_irep_t *file_rt); 245 0 stevel static void delRouteEntry(mib2_ipRouteEntry_t *rp, 246 0 stevel mib2_ipv6RouteEntry_t *rp6, int seqno); 247 1291 jl138328 static void del_rtcmd_irep(rtcmd_irep_t *rcip); 248 0 stevel static void flushroutes(int argc, char *argv[]); 249 1291 jl138328 static boolean_t getaddr(rtcmd_irep_t *rcip, int which, char *s, 250 1291 jl138328 addr_type_t atype); 251 0 stevel static boolean_t in6_getaddr(char *s, struct sockaddr_in6 *sin6, 252 0 stevel int *plenp, struct hostent **hpp); 253 0 stevel static boolean_t in_getaddr(char *s, struct sockaddr_in *sin, 254 1291 jl138328 int *plenp, int which, struct hostent **hpp, addr_type_t atype, 255 1291 jl138328 rtcmd_irep_t *rcip); 256 0 stevel static int in_getprefixlen(char *addr, int max_plen); 257 0 stevel static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 258 0 stevel uchar_t *mask); 259 1291 jl138328 static void inet_makenetandmask(rtcmd_irep_t *rcip, in_addr_t net, 260 0 stevel struct sockaddr_in *sin); 261 0 stevel static in_addr_t inet_makesubnetmask(in_addr_t addr, in_addr_t mask); 262 1291 jl138328 static int keyword(const char *cp); 263 0 stevel static void link_addr(const char *addr, struct sockaddr_dl *sdl); 264 0 stevel static char *link_ntoa(const struct sockaddr_dl *sdl); 265 0 stevel static mib_item_t *mibget(int sd); 266 0 stevel static char *netname(struct sockaddr *sa); 267 1291 jl138328 static int newroute(char **argv); 268 1291 jl138328 static rtcmd_irep_t *new_rtcmd_irep(void); 269 1676 jpk static void pmsg_addrs(const char *cp, size_t len, uint_t addrs); 270 1676 jpk static void pmsg_common(const struct rt_msghdr *rtm, size_t len); 271 1291 jl138328 static void print_getmsg(rtcmd_irep_t *req_rt, 272 1291 jl138328 struct rt_msghdr *rtm, int msglen); 273 1291 jl138328 static void print_rtcmd_short(FILE *to, rtcmd_irep_t *rcip, 274 1291 jl138328 boolean_t gw_good, boolean_t to_saved); 275 0 stevel static void print_rtmsg(struct rt_msghdr *rtm, int msglen); 276 192 carlsonj static void quit(char *s, int err) __NORETURN; 277 1676 jpk static char *routename(const struct sockaddr *sa); 278 0 stevel static void rtmonitor(int argc, char *argv[]); 279 1291 jl138328 static int rtmsg(rtcmd_irep_t *rcip); 280 1676 jpk static int salen(const struct sockaddr *sa); 281 1291 jl138328 static void save_route(int argc, char **argv, int do_flush); 282 1291 jl138328 static void save_string(char **dst, char *src); 283 1291 jl138328 static int search_rtfile(FILE *fp, FILE *temp_fp, rtcmd_irep_t *rt, 284 1291 jl138328 search_mode_t mode); 285 1291 jl138328 static void set_metric(rtcmd_irep_t *rcip, char *value, int key, 286 1291 jl138328 boolean_t lock); 287 1291 jl138328 static int show_saved_routes(int argc); 288 0 stevel static void sockaddr(char *addr, struct sockaddr *sa); 289 1291 jl138328 static void sodump(su_t *su, char *which); 290 1291 jl138328 static void syntax_arg_missing(char *keyword); 291 1291 jl138328 static void syntax_bad_keyword(char *keyword); 292 1291 jl138328 static void syntax_error(char *err, ...); 293 0 stevel static void usage(char *cp); 294 1291 jl138328 static void write_to_rtfile(FILE *fp, int argc, char **argv); 295 1676 jpk static void pmsg_secattr(const char *, size_t, const char *); 296 0 stevel 297 1291 jl138328 static pid_t pid; 298 0 stevel static int s; 299 1291 jl138328 static boolean_t nflag; 300 0 stevel static int af = AF_INET; 301 0 stevel static boolean_t qflag, tflag; 302 1291 jl138328 static boolean_t verbose; 303 1291 jl138328 static boolean_t debugonly; 304 0 stevel static boolean_t fflag; 305 1291 jl138328 static boolean_t update_table; 306 1291 jl138328 static boolean_t perm_flag; 307 1291 jl138328 static boolean_t early_v6_keyword; 308 1291 jl138328 static char perm_file_sfx[] = "/etc/inet/static_routes"; 309 1291 jl138328 static char *perm_file; 310 1291 jl138328 static char temp_file_sfx[] = "/etc/inet/static_routes.tmp"; 311 1291 jl138328 static char *temp_file; 312 1291 jl138328 static struct in6_addr in6_host_mask = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 313 1291 jl138328 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 314 1291 jl138328 /* 315 1291 jl138328 * WARNING: 316 1291 jl138328 * This next variable indicates whether certain functions exit when an error 317 1291 jl138328 * is detected in the user input. Currently, exit_on_error is only set false 318 1291 jl138328 * in search_rtfile(), when argument are being parsed. Only those functions 319 1291 jl138328 * used by search_rtfile() to parse its arguments are designed to work in 320 1291 jl138328 * both modes. Take particular care in setting this false to ensure that any 321 1291 jl138328 * functions you call that might act on this flag properly return errors when 322 1291 jl138328 * exit_on_error is false. 323 1291 jl138328 */ 324 1291 jl138328 static int exit_on_error = B_TRUE; 325 0 stevel 326 0 stevel static struct { 327 0 stevel struct rt_msghdr m_rtm; 328 1676 jpk char m_space[BUF_SIZE]; 329 0 stevel } m_rtmsg; 330 0 stevel 331 0 stevel /* 332 0 stevel * Sizes of data structures extracted from the base mib. 333 0 stevel * This allows the size of the tables entries to grow while preserving 334 0 stevel * binary compatibility. 335 0 stevel */ 336 0 stevel static int ipRouteEntrySize; 337 0 stevel static int ipv6RouteEntrySize; 338 0 stevel 339 0 stevel #define ROUNDUP_LONG(a) \ 340 0 stevel ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long)) 341 0 stevel #define ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n))) 342 0 stevel #define C(x) ((x) & 0xff) 343 0 stevel 344 0 stevel /* 345 0 stevel * return values from in_getprefixlen() 346 0 stevel */ 347 0 stevel #define BAD_ADDR -1 /* prefix is invalid */ 348 0 stevel #define NO_PREFIX -2 /* no prefix was found */ 349 1291 jl138328 350 0 stevel void 351 0 stevel usage(char *cp) 352 0 stevel { 353 1291 jl138328 if (cp != NULL) { 354 0 stevel (void) fprintf(stderr, gettext("route: botched keyword: %s\n"), 355 0 stevel cp); 356 1291 jl138328 } 357 1291 jl138328 (void) fprintf(stderr, gettext("usage: route [ -fnpqv ] " 358 1291 jl138328 "[ -R <root-dir> ] cmd [[ -<qualifers> ] args ]\n")); 359 0 stevel exit(1); 360 0 stevel /* NOTREACHED */ 361 1291 jl138328 } 362 1291 jl138328 363 1291 jl138328 /*PRINTFLIKE1*/ 364 1291 jl138328 void 365 1291 jl138328 syntax_error(char *err, ...) 366 1291 jl138328 { 367 1291 jl138328 va_list args; 368 1291 jl138328 369 1291 jl138328 if (exit_on_error) { 370 1291 jl138328 va_start(args, err); 371 1291 jl138328 (void) vfprintf(stderr, err, args); 372 1291 jl138328 va_end(args); 373 1291 jl138328 exit(1); 374 1291 jl138328 } 375 1291 jl138328 /* NOTREACHED */ 376 1291 jl138328 } 377 1291 jl138328 378 1291 jl138328 void 379 1291 jl138328 syntax_bad_keyword(char *keyword) 380 1291 jl138328 { 381 1291 jl138328 syntax_error(gettext("route: botched keyword: %s\n"), keyword); 382 1291 jl138328 } 383 1291 jl138328 384 1291 jl138328 void 385 1291 jl138328 syntax_arg_missing(char *keyword) 386 1291 jl138328 { 387 1291 jl138328 syntax_error(gettext("route: argument required following keyword %s\n"), 388 1291 jl138328 keyword); 389 0 stevel } 390 0 stevel 391 0 stevel void 392 0 stevel quit(char *s, int sverrno) 393 0 stevel { 394 0 stevel (void) fprintf(stderr, "route: "); 395 0 stevel if (s != NULL) 396 0 stevel (void) fprintf(stderr, "%s: ", s); 397 0 stevel (void) fprintf(stderr, "%s\n", strerror(sverrno)); 398 0 stevel exit(sverrno); 399 0 stevel /* NOTREACHED */ 400 0 stevel } 401 0 stevel 402 0 stevel int 403 0 stevel main(int argc, char **argv) 404 0 stevel { 405 0 stevel extern int optind; 406 1291 jl138328 extern char *optarg; 407 0 stevel int ch; 408 1291 jl138328 int rval; 409 1291 jl138328 size_t size; 410 1291 jl138328 const char *root_dir = NULL; 411 0 stevel 412 0 stevel (void) setlocale(LC_ALL, ""); 413 0 stevel 414 0 stevel #if !defined(TEXT_DOMAIN) 415 0 stevel #define TEXT_DOMAIN "SYS_TEST" 416 0 stevel #endif 417 0 stevel (void) textdomain(TEXT_DOMAIN); 418 0 stevel 419 0 stevel if (argc < 2) 420 1676 jpk usage(NULL); 421 0 stevel 422 1291 jl138328 while ((ch = getopt(argc, argv, "R:nqdtvfp")) != EOF) { 423 0 stevel switch (ch) { 424 0 stevel case 'n': 425 0 stevel nflag = B_TRUE; 426 0 stevel break; 427 0 stevel case 'q': 428 0 stevel qflag = B_TRUE; 429 0 stevel break; 430 0 stevel case 'v': 431 0 stevel verbose = B_TRUE; 432 0 stevel break; 433 0 stevel case 't': 434 0 stevel tflag = B_TRUE; 435 0 stevel break; 436 0 stevel case 'd': 437 0 stevel debugonly = B_TRUE; 438 0 stevel break; 439 0 stevel case 'f': 440 0 stevel fflag = B_TRUE; 441 0 stevel break; 442 1291 jl138328 case 'p': 443 1291 jl138328 perm_flag = B_TRUE; 444 1291 jl138328 break; 445 1291 jl138328 case 'R': 446 1291 jl138328 root_dir = optarg; 447 1291 jl138328 break; 448 0 stevel case '?': 449 0 stevel default: 450 1676 jpk usage(NULL); 451 0 stevel /* NOTREACHED */ 452 0 stevel } 453 0 stevel } 454 0 stevel argc -= optind; 455 0 stevel argv += optind; 456 0 stevel 457 0 stevel pid = getpid(); 458 0 stevel if (tflag) 459 0 stevel s = open("/dev/null", O_WRONLY); 460 0 stevel else 461 0 stevel s = socket(PF_ROUTE, SOCK_RAW, 0); 462 0 stevel if (s < 0) 463 0 stevel quit("socket", errno); 464 1291 jl138328 465 1291 jl138328 /* 466 1291 jl138328 * Handle the -p and -R flags. The -R flag only applies 467 1291 jl138328 * when the -p flag is set. 468 1291 jl138328 */ 469 1291 jl138328 if (root_dir == NULL) { 470 1291 jl138328 perm_file = perm_file_sfx; 471 1291 jl138328 temp_file = temp_file_sfx; 472 1291 jl138328 } else { 473 1291 jl138328 size = strlen(root_dir) + sizeof (perm_file_sfx); 474 1291 jl138328 perm_file = malloc(size); 475 1291 jl138328 if (perm_file == NULL) 476 1291 jl138328 quit("malloc", errno); 477 1291 jl138328 (void) snprintf(perm_file, size, "%s%s", root_dir, 478 1291 jl138328 perm_file_sfx); 479 1291 jl138328 size = strlen(root_dir) + sizeof (temp_file_sfx); 480 1291 jl138328 temp_file = malloc(size); 481 1291 jl138328 if (temp_file == NULL) 482 1291 jl138328 quit("malloc", errno); 483 1291 jl138328 (void) snprintf(temp_file, size, "%s%s", root_dir, 484 1291 jl138328 temp_file_sfx); 485 1291 jl138328 } 486 1291 jl138328 /* 487 1291 jl138328 * Whether or not to act on the routing table. The only time the 488 1291 jl138328 * routing table is not modified is when both -p and -R are present. 489 1291 jl138328 */ 490 1291 jl138328 update_table = (!perm_flag || root_dir == NULL); 491 1291 jl138328 if (tflag) 492 1291 jl138328 perm_flag = 0; 493 1291 jl138328 494 0 stevel if (fflag) { 495 0 stevel /* 496 0 stevel * Accept an address family keyword after the -f. Since the 497 0 stevel * default address family is AF_INET, reassign af only for the 498 0 stevel * other valid address families. 499 0 stevel */ 500 0 stevel if (*argv != NULL) { 501 1291 jl138328 switch (keyword(*argv)) { 502 1291 jl138328 case K_INET6: 503 1291 jl138328 af = AF_INET6; 504 1291 jl138328 early_v6_keyword = B_TRUE; 505 1291 jl138328 /* fallthrough */ 506 0 stevel case K_INET: 507 0 stevel /* Skip over the address family parameter. */ 508 0 stevel argc--; 509 0 stevel argv++; 510 0 stevel break; 511 0 stevel } 512 0 stevel } 513 156 dduvall flushroutes(0, NULL); 514 0 stevel } 515 1291 jl138328 516 0 stevel if (*argv != NULL) { 517 0 stevel switch (keyword(*argv)) { 518 0 stevel case K_GET: 519 0 stevel case K_CHANGE: 520 0 stevel case K_ADD: 521 0 stevel case K_DELETE: 522 1291 jl138328 rval = 0; 523 1291 jl138328 if (update_table) { 524 1291 jl138328 rval = newroute(argv); 525 1291 jl138328 } 526 1291 jl138328 if (perm_flag && (rval == 0 || rval == EEXIST || 527 1291 jl138328 rval == ESRCH)) { 528 1291 jl138328 save_route(argc, argv, B_FALSE); 529 1291 jl138328 return (0); 530 1291 jl138328 } 531 1291 jl138328 return (rval); 532 1291 jl138328 case K_SHOW: 533 1291 jl138328 if (perm_flag) { 534 1291 jl138328 return (show_saved_routes(argc)); 535 1291 jl138328 } else { 536 1291 jl138328 syntax_error(gettext( 537 1291 jl138328 "route: show command requires -p\n")); 538 1291 jl138328 } 539 1291 jl138328 /* NOTREACHED */ 540 0 stevel case K_MONITOR: 541 0 stevel rtmonitor(argc, argv); 542 0 stevel /* NOTREACHED */ 543 0 stevel 544 0 stevel case K_FLUSH: 545 0 stevel flushroutes(argc, argv); 546 1291 jl138328 return (0); 547 0 stevel } 548 0 stevel } 549 0 stevel if (!fflag) 550 0 stevel usage(*argv); 551 0 stevel return (0); 552 0 stevel } 553 0 stevel 554 0 stevel /* 555 0 stevel * Purge all entries in the routing tables not 556 0 stevel * associated with network interfaces. 557 0 stevel */ 558 0 stevel void 559 0 stevel flushroutes(int argc, char *argv[]) 560 0 stevel { 561 0 stevel int seqno; 562 0 stevel int sd; /* mib stream */ 563 0 stevel mib_item_t *item; 564 0 stevel mib2_ipRouteEntry_t *rp; 565 0 stevel mib2_ipv6RouteEntry_t *rp6; 566 0 stevel int oerrno; 567 0 stevel int off = 0; 568 0 stevel int on = 1; 569 0 stevel 570 0 stevel if (argc > 1) { 571 0 stevel argv++; 572 0 stevel if (argc == 2 && **argv == '-') { 573 0 stevel /* 574 0 stevel * The address family (preceded by a dash) may be used 575 0 stevel * to flush the routes of that particular family. 576 0 stevel */ 577 0 stevel switch (keyword(*argv + 1)) { 578 0 stevel case K_INET: 579 0 stevel af = AF_INET; 580 0 stevel break; 581 0 stevel case K_LINK: 582 0 stevel af = AF_LINK; 583 0 stevel break; 584 0 stevel case K_INET6: 585 0 stevel af = AF_INET6; 586 0 stevel break; 587 0 stevel default: 588 0 stevel usage(*argv); 589 0 stevel /* NOTREACHED */ 590 0 stevel } 591 0 stevel } else { 592 0 stevel usage(*argv); 593 0 stevel } 594 0 stevel } 595 1291 jl138328 if (perm_flag) { 596 1291 jl138328 /* This flushes the persistent route file */ 597 1291 jl138328 save_route(0, NULL, B_TRUE); 598 1291 jl138328 } 599 1291 jl138328 if (!update_table) { 600 1291 jl138328 return; 601 1291 jl138328 } 602 1291 jl138328 603 1291 jl138328 if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off, 604 1291 jl138328 sizeof (off)) < 0) 605 1291 jl138328 quit("setsockopt", errno); 606 1291 jl138328 607 0 stevel sd = open("/dev/ip", O_RDWR); 608 0 stevel oerrno = errno; 609 0 stevel if (sd < 0) { 610 0 stevel switch (errno) { 611 0 stevel case EACCES: 612 0 stevel (void) fprintf(stderr, 613 0 stevel gettext("route: flush: insufficient privileges\n")); 614 0 stevel exit(oerrno); 615 0 stevel /* NOTREACHED */ 616 0 stevel default: 617 0 stevel quit(gettext("can't open mib stream"), oerrno); 618 0 stevel /* NOTREACHED */ 619 0 stevel } 620 0 stevel } 621 0 stevel if ((item = mibget(sd)) == NULL) 622 0 stevel quit("mibget", errno); 623 0 stevel if (verbose) { 624 0 stevel (void) printf("Examining routing table from " 625 0 stevel "T_SVR4_OPTMGMT_REQ\n"); 626 0 stevel } 627 0 stevel seqno = 0; /* ??? */ 628 0 stevel switch (af) { 629 0 stevel case AF_INET: 630 0 stevel /* Extract ipRouteEntrySize */ 631 0 stevel for (; item != NULL; item = item->next_item) { 632 0 stevel if (item->mib_id != 0) 633 0 stevel continue; 634 0 stevel if (item->group == MIB2_IP) { 635 0 stevel ipRouteEntrySize = 636 0 stevel ((mib2_ip_t *)item->valp)->ipRouteEntrySize; 637 0 stevel assert(IS_P2ALIGNED(ipRouteEntrySize, 638 0 stevel sizeof (mib2_ipRouteEntry_t *))); 639 0 stevel break; 640 0 stevel } 641 0 stevel } 642 0 stevel if (ipRouteEntrySize == 0) { 643 0 stevel (void) fprintf(stderr, 644 0 stevel gettext("ipRouteEntrySize can't be determined.\n")); 645 0 stevel exit(1); 646 0 stevel } 647 0 stevel for (; item != NULL; item = item->next_item) { 648 0 stevel /* 649 0 stevel * skip all the other trash that comes up the mib stream 650 0 stevel */ 651 0 stevel if (item->group != MIB2_IP || 652 0 stevel item->mib_id != MIB2_IP_ROUTE) 653 0 stevel continue; 654 0 stevel for (rp = (mib2_ipRouteEntry_t *)item->valp; 655 0 stevel (char *)rp < (char *)item->valp + item->length; 656 0 stevel /* LINTED */ 657 0 stevel rp = (mib2_ipRouteEntry_t *) 658 11042 Erik ((char *)rp + ipRouteEntrySize)) { 659 0 stevel delRouteEntry(rp, NULL, seqno); 660 0 stevel seqno++; 661 0 stevel } 662 0 stevel break; 663 0 stevel } 664 0 stevel break; 665 0 stevel case AF_INET6: 666 0 stevel /* Extract ipv6RouteEntrySize */ 667 0 stevel for (; item != NULL; item = item->next_item) { 668 0 stevel if (item->mib_id != 0) 669 0 stevel continue; 670 0 stevel if (item->group == MIB2_IP6) { 671 0 stevel ipv6RouteEntrySize = 672 0 stevel ((mib2_ipv6IfStatsEntry_t *)item->valp)-> 673 11042 Erik ipv6RouteEntrySize; 674 0 stevel assert(IS_P2ALIGNED(ipv6RouteEntrySize, 675 0 stevel sizeof (mib2_ipv6RouteEntry_t *))); 676 0 stevel break; 677 0 stevel } 678 0 stevel } 679 0 stevel if (ipv6RouteEntrySize == 0) { 680 0 stevel (void) fprintf(stderr, gettext( 681 0 stevel "ipv6RouteEntrySize cannot be determined.\n")); 682 0 stevel exit(1); 683 0 stevel } 684 0 stevel for (; item != NULL; item = item->next_item) { 685 0 stevel /* 686 0 stevel * skip all the other trash that comes up the mib stream 687 0 stevel */ 688 0 stevel if (item->group != MIB2_IP6 || 689 0 stevel item->mib_id != MIB2_IP6_ROUTE) 690 0 stevel continue; 691 0 stevel for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp; 692 0 stevel (char *)rp6 < (char *)item->valp + item->length; 693 0 stevel /* LINTED */ 694 0 stevel rp6 = (mib2_ipv6RouteEntry_t *) 695 11042 Erik ((char *)rp6 + ipv6RouteEntrySize)) { 696 0 stevel delRouteEntry(NULL, rp6, seqno); 697 0 stevel seqno++; 698 0 stevel } 699 0 stevel break; 700 0 stevel } 701 0 stevel break; 702 0 stevel } 703 0 stevel 704 0 stevel if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, 705 0 stevel sizeof (on)) < 0) 706 0 stevel quit("setsockopt", errno); 707 0 stevel } 708 0 stevel 709 0 stevel /* 710 0 stevel * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or 711 0 stevel * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in 712 0 stevel * order to facilitate the flushing of RTF_GATEWAY routes. 713 0 stevel */ 714 0 stevel static void 715 0 stevel delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno) 716 0 stevel { 717 0 stevel char *cp; 718 0 stevel int ire_type; 719 0 stevel int rlen; 720 0 stevel struct rt_msghdr *rtm; 721 0 stevel struct sockaddr_in sin; 722 0 stevel struct sockaddr_in6 sin6; 723 0 stevel int slen; 724 0 stevel 725 0 stevel if (rp != NULL) 726 0 stevel ire_type = rp->ipRouteInfo.re_ire_type; 727 0 stevel else 728 0 stevel ire_type = rp6->ipv6RouteInfo.re_ire_type; 729 0 stevel if (ire_type != IRE_DEFAULT && 730 0 stevel ire_type != IRE_PREFIX && 731 0 stevel ire_type != IRE_HOST && 732 0 stevel ire_type != IRE_HOST_REDIRECT) 733 0 stevel return; 734 0 stevel 735 0 stevel rtm = &m_rtmsg.m_rtm; 736 0 stevel (void) memset(rtm, 0, sizeof (m_rtmsg)); 737 0 stevel rtm->rtm_type = RTM_DELETE; 738 0 stevel rtm->rtm_seq = seqno; 739 0 stevel rtm->rtm_flags |= RTF_GATEWAY; 740 0 stevel rtm->rtm_version = RTM_VERSION; 741 0 stevel rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 742 0 stevel cp = m_rtmsg.m_space; 743 0 stevel if (rp != NULL) { 744 0 stevel slen = sizeof (struct sockaddr_in); 745 0 stevel if (rp->ipRouteMask == IP_HOST_MASK) 746 0 stevel rtm->rtm_flags |= RTF_HOST; 747 0 stevel (void) memset(&sin, 0, slen); 748 0 stevel sin.sin_family = AF_INET; 749 0 stevel sin.sin_addr.s_addr = rp->ipRouteDest; 750 0 stevel (void) memmove(cp, &sin, slen); 751 0 stevel cp += slen; 752 0 stevel sin.sin_addr.s_addr = rp->ipRouteNextHop; 753 0 stevel (void) memmove(cp, &sin, slen); 754 0 stevel cp += slen; 755 0 stevel sin.sin_addr.s_addr = rp->ipRouteMask; 756 0 stevel (void) memmove(cp, &sin, slen); 757 0 stevel cp += slen; 758 0 stevel } else { 759 0 stevel slen = sizeof (struct sockaddr_in6); 760 0 stevel if (rp6->ipv6RoutePfxLength == IPV6_ABITS) 761 0 stevel rtm->rtm_flags |= RTF_HOST; 762 0 stevel (void) memset(&sin6, 0, slen); 763 0 stevel sin6.sin6_family = AF_INET6; 764 0 stevel sin6.sin6_addr = rp6->ipv6RouteDest; 765 0 stevel (void) memmove(cp, &sin6, slen); 766 0 stevel cp += slen; 767 0 stevel sin6.sin6_addr = rp6->ipv6RouteNextHop; 768 0 stevel (void) memmove(cp, &sin6, slen); 769 0 stevel cp += slen; 770 0 stevel (void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr)); 771 0 stevel (void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS, 772 0 stevel (uchar_t *)&sin6.sin6_addr.s6_addr); 773 0 stevel (void) memmove(cp, &sin6, slen); 774 0 stevel cp += slen; 775 0 stevel } 776 0 stevel rtm->rtm_msglen = cp - (char *)&m_rtmsg; 777 0 stevel if (debugonly) { 778 0 stevel /* 779 0 stevel * In debugonly mode, the routing socket message to delete the 780 0 stevel * current entry is not actually sent. However if verbose is 781 0 stevel * also set, the routing socket message that would have been 782 0 stevel * is printed. 783 0 stevel */ 784 0 stevel if (verbose) 785 0 stevel print_rtmsg(rtm, rtm->rtm_msglen); 786 0 stevel return; 787 0 stevel } 788 0 stevel 789 0 stevel rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen); 790 0 stevel if (rlen < (int)rtm->rtm_msglen) { 791 0 stevel if (rlen < 0) { 792 0 stevel (void) fprintf(stderr, 793 0 stevel gettext("route: write to routing socket: %s\n"), 794 0 stevel strerror(errno)); 795 0 stevel } else { 796 0 stevel (void) fprintf(stderr, gettext("route: write to " 797 0 stevel "routing socket got only %d for rlen\n"), rlen); 798 0 stevel } 799 0 stevel return; 800 0 stevel } 801 0 stevel if (qflag) { 802 0 stevel /* 803 0 stevel * In quiet mode, nothing is printed at all (unless the write() 804 0 stevel * itself failed. 805 0 stevel */ 806 0 stevel return; 807 0 stevel } 808 0 stevel if (verbose) { 809 0 stevel print_rtmsg(rtm, rlen); 810 0 stevel } else { 811 0 stevel struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 812 0 stevel 813 0 stevel (void) printf("%-20.20s ", 814 0 stevel rtm->rtm_flags & RTF_HOST ? routename(sa) : 815 11042 Erik netname(sa)); 816 0 stevel /* LINTED */ 817 0 stevel sa = (struct sockaddr *)(salen(sa) + (char *)sa); 818 0 stevel (void) printf("%-20.20s ", routename(sa)); 819 0 stevel (void) printf("done\n"); 820 0 stevel } 821 0 stevel } 822 0 stevel 823 0 stevel /* 824 0 stevel * Return the name of the host whose address is given. 825 0 stevel */ 826 0 stevel char * 827 1676 jpk routename(const struct sockaddr *sa) 828 0 stevel { 829 0 stevel char *cp; 830 0 stevel static char line[MAXHOSTNAMELEN + 1]; 831 0 stevel struct hostent *hp = NULL; 832 0 stevel static char domain[MAXHOSTNAMELEN + 1]; 833 0 stevel static boolean_t first = B_TRUE; 834 0 stevel struct in_addr in; 835 0 stevel struct in6_addr in6; 836 0 stevel int error_num; 837 0 stevel ushort_t *s; 838 0 stevel ushort_t *slim; 839 0 stevel 840 0 stevel if (first) { 841 0 stevel first = B_FALSE; 842 0 stevel if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 843 0 stevel (cp = strchr(domain, '.'))) 844 0 stevel (void) strcpy(domain, cp + 1); 845 0 stevel else 846 0 stevel domain[0] = 0; 847 0 stevel } 848 0 stevel 849 0 stevel if (salen(sa) == 0) { 850 0 stevel (void) strcpy(line, "default"); 851 0 stevel return (line); 852 0 stevel } 853 0 stevel switch (sa->sa_family) { 854 0 stevel 855 0 stevel case AF_INET: 856 0 stevel /* LINTED */ 857 0 stevel in = ((struct sockaddr_in *)sa)->sin_addr; 858 0 stevel 859 0 stevel cp = NULL; 860 0 stevel if (in.s_addr == INADDR_ANY) 861 0 stevel cp = "default"; 862 0 stevel if (cp == NULL && !nflag) { 863 0 stevel hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 864 11042 Erik AF_INET); 865 0 stevel if (hp != NULL) { 866 0 stevel if (((cp = strchr(hp->h_name, '.')) != NULL) && 867 0 stevel (strcmp(cp + 1, domain) == 0)) 868 0 stevel *cp = 0; 869 0 stevel cp = hp->h_name; 870 0 stevel } 871 0 stevel } 872 0 stevel if (cp != NULL) { 873 0 stevel (void) strncpy(line, cp, MAXHOSTNAMELEN); 874 0 stevel line[MAXHOSTNAMELEN] = '\0'; 875 0 stevel } else { 876 0 stevel in.s_addr = ntohl(in.s_addr); 877 0 stevel (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 878 0 stevel C(in.s_addr >> 16), C(in.s_addr >> 8), 879 0 stevel C(in.s_addr)); 880 0 stevel } 881 0 stevel break; 882 0 stevel 883 0 stevel case AF_LINK: 884 0 stevel return (link_ntoa((struct sockaddr_dl *)sa)); 885 0 stevel 886 0 stevel case AF_INET6: 887 0 stevel /* LINTED */ 888 0 stevel in6 = ((struct sockaddr_in6 *)sa)->sin6_addr; 889 0 stevel 890 0 stevel cp = NULL; 891 0 stevel if (IN6_IS_ADDR_UNSPECIFIED(&in6)) 892 0 stevel cp = "default"; 893 0 stevel if (cp == NULL && !nflag) { 894 0 stevel hp = getipnodebyaddr((char *)&in6, 895 11042 Erik sizeof (struct in6_addr), AF_INET6, &error_num); 896 0 stevel if (hp != NULL) { 897 0 stevel if (((cp = strchr(hp->h_name, '.')) != NULL) && 898 0 stevel (strcmp(cp + 1, domain) == 0)) 899 0 stevel *cp = 0; 900 0 stevel cp = hp->h_name; 901 0 stevel } 902 0 stevel } 903 0 stevel if (cp != NULL) { 904 0 stevel (void) strncpy(line, cp, MAXHOSTNAMELEN); 905 0 stevel line[MAXHOSTNAMELEN] = '\0'; 906 0 stevel } else { 907 0 stevel (void) inet_ntop(AF_INET6, (void *)&in6, line, 908 0 stevel INET6_ADDRSTRLEN); 909 0 stevel } 910 0 stevel if (hp != NULL) 911 0 stevel freehostent(hp); 912 0 stevel 913 0 stevel break; 914 0 stevel 915 0 stevel default: 916 0 stevel s = (ushort_t *)sa; 917 0 stevel 918 0 stevel slim = s + ((salen(sa) + 1) >> 1); 919 0 stevel cp = line + sprintf(line, "(%d)", sa->sa_family); 920 0 stevel 921 0 stevel while (++s < slim) /* start with sa->sa_data */ 922 0 stevel cp += sprintf(cp, " %x", *s); 923 0 stevel break; 924 0 stevel } 925 0 stevel return (line); 926 0 stevel } 927 0 stevel 928 0 stevel /* 929 0 stevel * Return the name of the network whose address is given. 930 0 stevel * The address is assumed to be that of a net or subnet, not a host. 931 0 stevel */ 932 0 stevel static char * 933 0 stevel netname(struct sockaddr *sa) 934 0 stevel { 935 0 stevel char *cp = NULL; 936 0 stevel static char line[MAXHOSTNAMELEN + 1]; 937 0 stevel struct netent *np; 938 0 stevel in_addr_t net, mask; 939 0 stevel int subnetshift; 940 0 stevel struct in_addr in; 941 0 stevel ushort_t *s; 942 0 stevel ushort_t *slim; 943 0 stevel 944 0 stevel switch (sa->sa_family) { 945 0 stevel 946 0 stevel case AF_INET: 947 0 stevel /* LINTED */ 948 0 stevel in = ((struct sockaddr_in *)sa)->sin_addr; 949 0 stevel 950 0 stevel in.s_addr = ntohl(in.s_addr); 951 0 stevel if (in.s_addr == INADDR_ANY) { 952 0 stevel cp = "default"; 953 0 stevel } else if (!nflag) { 954 0 stevel if (IN_CLASSA(in.s_addr)) { 955 0 stevel mask = IN_CLASSA_NET; 956 0 stevel subnetshift = 8; 957 0 stevel } else if (IN_CLASSB(in.s_addr)) { 958 0 stevel mask = IN_CLASSB_NET; 959 0 stevel subnetshift = 8; 960 0 stevel } else { 961 0 stevel mask = IN_CLASSC_NET; 962 0 stevel subnetshift = 4; 963 0 stevel } 964 0 stevel /* 965 0 stevel * If there are more bits than the standard mask 966 0 stevel * would suggest, subnets must be in use. 967 0 stevel * Guess at the subnet mask, assuming reasonable 968 0 stevel * width subnet fields. 969 0 stevel */ 970 0 stevel while (in.s_addr &~ mask) 971 0 stevel mask = (long)mask >> subnetshift; 972 0 stevel net = in.s_addr & mask; 973 0 stevel while ((mask & 1) == 0) 974 0 stevel mask >>= 1, net >>= 1; 975 0 stevel np = getnetbyaddr(net, AF_INET); 976 0 stevel if (np != NULL) 977 0 stevel cp = np->n_name; 978 0 stevel } 979 0 stevel if (cp != NULL) { 980 0 stevel (void) strncpy(line, cp, MAXHOSTNAMELEN); 981 0 stevel line[MAXHOSTNAMELEN] = '\0'; 982 0 stevel } else if ((in.s_addr & 0xffffff) == 0) { 983 0 stevel (void) sprintf(line, "%u", C(in.s_addr >> 24)); 984 0 stevel } else if ((in.s_addr & 0xffff) == 0) { 985 0 stevel (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 986 0 stevel C(in.s_addr >> 16)); 987 0 stevel } else if ((in.s_addr & 0xff) == 0) { 988 0 stevel (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 989 0 stevel C(in.s_addr >> 16), C(in.s_addr >> 8)); 990 0 stevel } else { 991 0 stevel (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 992 0 stevel C(in.s_addr >> 16), C(in.s_addr >> 8), 993 0 stevel C(in.s_addr)); 994 0 stevel } 995 0 stevel break; 996 0 stevel 997 0 stevel case AF_LINK: 998 0 stevel return (link_ntoa((struct sockaddr_dl *)sa)); 999 0 stevel 1000 0 stevel case AF_INET6: 1001 0 stevel return (routename(sa)); 1002 0 stevel 1003 0 stevel default: 1004 0 stevel /* LINTED */ 1005 0 stevel s = (ushort_t *)sa->sa_data; 1006 0 stevel 1007 0 stevel slim = s + ((salen(sa) + 1) >> 1); 1008 0 stevel cp = line + sprintf(line, "af %d:", sa->sa_family); 1009 0 stevel 1010 0 stevel while (s < slim) 1011 0 stevel cp += sprintf(cp, " %x", *s++); 1012 0 stevel break; 1013 0 stevel } 1014 0 stevel return (line); 1015 0 stevel } 1016 0 stevel 1017 1291 jl138328 /* 1018 1291 jl138328 * Initialize a new structure. Keep in mind that ri_dst_str, ri_gate_str and 1019 1291 jl138328 * ri_ifp_str will be freed by det_rtcmd_irep, so they should either be NULL 1020 1291 jl138328 * or point to dynamically allocated memory. 1021 1291 jl138328 */ 1022 1291 jl138328 rtcmd_irep_t * 1023 1291 jl138328 new_rtcmd_irep(void) 1024 1291 jl138328 { 1025 1291 jl138328 rtcmd_irep_t *rcip; 1026 1291 jl138328 1027 1291 jl138328 rcip = calloc(1, sizeof (rtcmd_irep_t)); 1028 1291 jl138328 if (rcip == NULL) { 1029 1291 jl138328 quit("calloc", errno); 1030 1291 jl138328 } 1031 1291 jl138328 rcip->ri_af = af; 1032 1291 jl138328 rcip->ri_flags = RTF_STATIC; 1033 1291 jl138328 return (rcip); 1034 1291 jl138328 } 1035 1291 jl138328 1036 0 stevel void 1037 1291 jl138328 del_rtcmd_irep(rtcmd_irep_t *rcip) 1038 1291 jl138328 { 1039 1291 jl138328 free(rcip->ri_dest_str); 1040 1291 jl138328 free(rcip->ri_gate_str); 1041 1291 jl138328 free(rcip->ri_ifp_str); 1042 3846 dg199075 /* 1043 3846 dg199075 * IPv6 host entries come from getipnodebyname, which dynamically 1044 3846 dg199075 * allocates memory. IPv4 host entries come from gethostbyname, which 1045 3846 dg199075 * returns static memory and cannot be freed with freehostent. 1046 3846 dg199075 */ 1047 3846 dg199075 if (rcip->ri_gate_hp != NULL && 1048 3846 dg199075 rcip->ri_gate_hp->h_addrtype == AF_INET6) 1049 1291 jl138328 freehostent(rcip->ri_gate_hp); 1050 1291 jl138328 free(rcip); 1051 1291 jl138328 } 1052 1291 jl138328 1053 1291 jl138328 void 1054 1291 jl138328 save_string(char **dst, char *src) 1055 1291 jl138328 { 1056 1291 jl138328 free(*dst); 1057 1291 jl138328 *dst = strdup(src); 1058 1291 jl138328 if (*dst == NULL) { 1059 1291 jl138328 quit("malloc", errno); 1060 1291 jl138328 } 1061 1291 jl138328 } 1062 1291 jl138328 1063 1291 jl138328 /* 1064 1291 jl138328 * Print the short form summary of a route command. 1065 1291 jl138328 * Eg. "add net default: gateway 10.0.0.1" 1066 1291 jl138328 * The final newline is not added, allowing the caller to append additional 1067 1291 jl138328 * information. 1068 1291 jl138328 */ 1069 1291 jl138328 void 1070 1291 jl138328 print_rtcmd_short(FILE *to, rtcmd_irep_t *rcip, boolean_t gw_good, 1071 1291 jl138328 boolean_t to_saved) 1072 1291 jl138328 { 1073 1291 jl138328 char *cmd; 1074 1291 jl138328 char obuf[INET6_ADDRSTRLEN]; 1075 1291 jl138328 1076 1291 jl138328 switch (rcip->ri_cmd) { 1077 1291 jl138328 case RTM_ADD: 1078 1291 jl138328 cmd = "add"; 1079 1291 jl138328 break; 1080 1291 jl138328 case RTM_CHANGE: 1081 1291 jl138328 cmd = "change"; 1082 1291 jl138328 break; 1083 1291 jl138328 case RTM_DELETE: 1084 1291 jl138328 cmd = "delete"; 1085 1291 jl138328 break; 1086 1291 jl138328 case RTM_GET: 1087 1291 jl138328 cmd = "get"; 1088 1291 jl138328 break; 1089 1291 jl138328 default: 1090 1291 jl138328 assert(0); 1091 1291 jl138328 } 1092 1291 jl138328 1093 1291 jl138328 (void) fprintf(to, "%s%s %s %s", cmd, 1094 1291 jl138328 (to_saved) ? " persistent" : "", 1095 1291 jl138328 (rcip->ri_flags & RTF_HOST) ? "host" : "net", 1096 1291 jl138328 (rcip->ri_dest_str == NULL) ? "NULL" : rcip->ri_dest_str); 1097 1291 jl138328 1098 1291 jl138328 if (rcip->ri_gate_str != NULL) { 1099 1291 jl138328 switch (rcip->ri_af) { 1100 1291 jl138328 case AF_INET: 1101 1291 jl138328 if (nflag) { 1102 1291 jl138328 (void) fprintf(to, ": gateway %s", 1103 1291 jl138328 inet_ntoa(rcip->ri_gate.sin.sin_addr)); 1104 1291 jl138328 } else if (gw_good && 1105 1291 jl138328 rcip->ri_gate_hp != NULL && 1106 1291 jl138328 rcip->ri_gate_hp->h_addr_list[1] != NULL) { 1107 1291 jl138328 /* 1108 1291 jl138328 * Print the actual address used in the case 1109 1291 jl138328 * where there was more than one address 1110 1291 jl138328 * available for the name, and one was used 1111 1291 jl138328 * successfully. 1112 1291 jl138328 */ 1113 1291 jl138328 (void) fprintf(to, ": gateway %s (%s)", 1114 1291 jl138328 rcip->ri_gate_str, 1115 1291 jl138328 inet_ntoa(rcip->ri_gate.sin.sin_addr)); 1116 1291 jl138328 } else { 1117 1291 jl138328 (void) fprintf(to, ": gateway %s", 1118 1291 jl138328 rcip->ri_gate_str); 1119 1291 jl138328 } 1120 1291 jl138328 break; 1121 1291 jl138328 case AF_INET6: 1122 1291 jl138328 if (inet_ntop(AF_INET6, 1123 11042 Erik &rcip->ri_gate.sin6.sin6_addr, obuf, 1124 11042 Erik INET6_ADDRSTRLEN) != NULL) { 1125 1291 jl138328 if (nflag) { 1126 1291 jl138328 (void) fprintf(to, ": gateway %s", 1127 1291 jl138328 obuf); 1128 1291 jl138328 break; 1129 1291 jl138328 } 1130 1291 jl138328 if (gw_good && 1131 1291 jl138328 rcip->ri_gate_hp->h_addr_list[1] != NULL) { 1132 1291 jl138328 (void) fprintf(to, ": gateway %s (%s)", 1133 1291 jl138328 rcip->ri_gate_str, obuf); 1134 1291 jl138328 break; 1135 1291 jl138328 } 1136 1291 jl138328 } 1137 1291 jl138328 /* FALLTHROUGH */ 1138 1291 jl138328 default: 1139 1291 jl138328 (void) fprintf(to, ": gateway %s", 1140 1291 jl138328 rcip->ri_gate_str); 1141 1291 jl138328 break; 1142 1291 jl138328 } 1143 1291 jl138328 } 1144 1291 jl138328 } 1145 1291 jl138328 1146 1291 jl138328 void 1147 1291 jl138328 set_metric(rtcmd_irep_t *rcip, char *value, int key, boolean_t lock) 1148 0 stevel { 1149 0 stevel int flag = 0; 1150 0 stevel uint_t noval, *valp = &noval; 1151 0 stevel 1152 0 stevel switch (key) { 1153 1291 jl138328 #define caseof(x, y, z) \ 1154 1291 jl138328 case (x): valp = &(rcip->ri_metrics.z); flag = (y); break 1155 1291 jl138328 1156 0 stevel caseof(K_MTU, RTV_MTU, rmx_mtu); 1157 0 stevel caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 1158 0 stevel caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 1159 0 stevel caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 1160 0 stevel caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 1161 0 stevel caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 1162 0 stevel caseof(K_RTT, RTV_RTT, rmx_rtt); 1163 0 stevel caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 1164 0 stevel #undef caseof 1165 0 stevel } 1166 1291 jl138328 rcip->ri_inits |= flag; 1167 1291 jl138328 if (lock) 1168 1291 jl138328 rcip->ri_metrics.rmx_locks |= flag; 1169 0 stevel *valp = atoi(value); 1170 0 stevel } 1171 0 stevel 1172 1291 jl138328 /* 1173 1291 jl138328 * Parse the options give in argv[], filling in rcip with the results. 1174 1291 jl138328 * If cmd_string is non-null, argc and argv are ignored, and cmd_string is 1175 1291 jl138328 * tokenized to produce the command line. Cmd_string is tokenized using 1176 1291 jl138328 * strtok, which will overwrite whitespace in the string with nulls. 1177 1291 jl138328 * 1178 1291 jl138328 * Returns B_TRUE on success and B_FALSE on failure. 1179 1291 jl138328 */ 1180 1291 jl138328 boolean_t 1181 1291 jl138328 args_to_rtcmd(rtcmd_irep_t *rcip, char **argv, char *cmd_string) 1182 0 stevel { 1183 1291 jl138328 const char *ws = "\f\n\r\t\v "; 1184 1291 jl138328 char *tok = cmd_string; 1185 1291 jl138328 char *keyword_str; 1186 1291 jl138328 addr_type_t atype = ADDR_TYPE_ANY; 1187 1291 jl138328 boolean_t iflag = B_FALSE; 1188 1291 jl138328 boolean_t locknext = B_FALSE; 1189 1291 jl138328 boolean_t lockrest = B_FALSE; 1190 1291 jl138328 boolean_t dash_keyword; 1191 0 stevel int key; 1192 1291 jl138328 char *err; 1193 0 stevel 1194 1291 jl138328 if (cmd_string == NULL) { 1195 1291 jl138328 tok = argv[0]; 1196 1291 jl138328 } else { 1197 1291 jl138328 tok = strtok(cmd_string, ws); 1198 0 stevel } 1199 1291 jl138328 1200 1291 jl138328 /* 1201 1291 jl138328 * The command keywords are already fully checked by main() or 1202 1291 jl138328 * search_rtfile(). 1203 1291 jl138328 */ 1204 1291 jl138328 switch (*tok) { 1205 1291 jl138328 case 'a': 1206 1291 jl138328 rcip->ri_cmd = RTM_ADD; 1207 1291 jl138328 break; 1208 1291 jl138328 case 'c': 1209 1291 jl138328 rcip->ri_cmd = RTM_CHANGE; 1210 1291 jl138328 break; 1211 1291 jl138328 case 'd': 1212 1291 jl138328 rcip->ri_cmd = RTM_DELETE; 1213 1291 jl138328 break; 1214 1291 jl138328 case 'g': 1215 1291 jl138328 rcip->ri_cmd = RTM_GET; 1216 1291 jl138328 break; 1217 1291 jl138328 default: 1218 1291 jl138328 /* NOTREACHED */ 1219 1291 jl138328 quit(gettext("Internal Error"), EINVAL); 1220 1291 jl138328 /* NOTREACHED */ 1221 1291 jl138328 } 1222 1291 jl138328 1223 1291 jl138328 #define NEXTTOKEN \ 1224 1291 jl138328 ((tok = (cmd_string == NULL ? *++argv : strtok(NULL, ws))) != NULL) 1225 1291 jl138328 1226 1291 jl138328 while (NEXTTOKEN) { 1227 1291 jl138328 keyword_str = tok; 1228 1291 jl138328 if (*tok == '-') { 1229 1291 jl138328 dash_keyword = B_TRUE; 1230 1291 jl138328 key = keyword(tok + 1); 1231 1291 jl138328 } else { 1232 1291 jl138328 dash_keyword = B_FALSE; 1233 1291 jl138328 key = keyword(tok); 1234 1291 jl138328 if (key != K_HOST && key != K_NET) { 1235 1291 jl138328 /* All others must be preceded by '-' */ 1236 1291 jl138328 key = 0; 1237 1291 jl138328 } 1238 1291 jl138328 } 1239 1291 jl138328 switch (key) { 1240 1291 jl138328 case K_HOST: 1241 1291 jl138328 if (atype == ADDR_TYPE_NET) { 1242 1291 jl138328 syntax_error(gettext("route: -host and -net " 1243 1291 jl138328 "are mutually exclusive\n")); 1244 1291 jl138328 return (B_FALSE); 1245 1291 jl138328 } 1246 1291 jl138328 atype = ADDR_TYPE_HOST; 1247 1291 jl138328 break; 1248 1291 jl138328 case K_NET: 1249 1291 jl138328 if (atype == ADDR_TYPE_HOST) { 1250 1291 jl138328 syntax_error(gettext("route: -host and -net " 1251 1291 jl138328 "are mutually exclusive\n")); 1252 1291 jl138328 return (B_FALSE); 1253 1291 jl138328 } 1254 1291 jl138328 atype = ADDR_TYPE_NET; 1255 1291 jl138328 break; 1256 1291 jl138328 case K_LINK: 1257 1291 jl138328 rcip->ri_af = AF_LINK; 1258 1291 jl138328 break; 1259 1291 jl138328 case K_INET: 1260 1291 jl138328 rcip->ri_af = AF_INET; 1261 1291 jl138328 break; 1262 1291 jl138328 case K_SA: 1263 1291 jl138328 rcip->ri_af = PF_ROUTE; 1264 1291 jl138328 break; 1265 1291 jl138328 case K_INET6: 1266 1291 jl138328 rcip->ri_af = AF_INET6; 1267 1291 jl138328 break; 1268 1291 jl138328 case K_IFACE: 1269 1291 jl138328 case K_INTERFACE: 1270 1291 jl138328 iflag = B_TRUE; 1271 1291 jl138328 /* fallthrough */ 1272 1291 jl138328 case K_NOSTATIC: 1273 1291 jl138328 rcip->ri_flags &= ~RTF_STATIC; 1274 1291 jl138328 break; 1275 1291 jl138328 case K_LOCK: 1276 1291 jl138328 locknext = B_TRUE; 1277 1291 jl138328 break; 1278 1291 jl138328 case K_LOCKREST: 1279 1291 jl138328 lockrest = B_TRUE; 1280 1291 jl138328 break; 1281 1291 jl138328 case K_REJECT: 1282 1291 jl138328 rcip->ri_flags |= RTF_REJECT; 1283 1291 jl138328 break; 1284 1291 jl138328 case K_BLACKHOLE: 1285 1291 jl138328 rcip->ri_flags |= RTF_BLACKHOLE; 1286 1291 jl138328 break; 1287 1291 jl138328 case K_PROTO1: 1288 1291 jl138328 rcip->ri_flags |= RTF_PROTO1; 1289 1291 jl138328 break; 1290 1291 jl138328 case K_PROTO2: 1291 1291 jl138328 rcip->ri_flags |= RTF_PROTO2; 1292 1291 jl138328 break; 1293 1291 jl138328 case K_CLONING: 1294 1291 jl138328 rcip->ri_flags |= RTF_CLONING; 1295 1291 jl138328 break; 1296 1291 jl138328 case K_XRESOLVE: 1297 1291 jl138328 rcip->ri_flags |= RTF_XRESOLVE; 1298 1291 jl138328 break; 1299 1291 jl138328 case K_STATIC: 1300 1291 jl138328 rcip->ri_flags |= RTF_STATIC; 1301 1291 jl138328 break; 1302 1291 jl138328 case K_IFA: 1303 1291 jl138328 if (!NEXTTOKEN) { 1304 1291 jl138328 syntax_arg_missing(keyword_str); 1305 1291 jl138328 return (B_FALSE); 1306 1291 jl138328 } 1307 1291 jl138328 if (!getaddr(rcip, RTA_IFA, tok, atype)) { 1308 1291 jl138328 return (B_FALSE); 1309 1291 jl138328 } 1310 1291 jl138328 break; 1311 1291 jl138328 case K_IFP: 1312 1291 jl138328 if (!NEXTTOKEN) { 1313 1291 jl138328 syntax_arg_missing(keyword_str); 1314 1291 jl138328 return (B_FALSE); 1315 1291 jl138328 } 1316 1291 jl138328 if (!getaddr(rcip, RTA_IFP, tok, atype)) { 1317 1291 jl138328 return (B_FALSE); 1318 1291 jl138328 } 1319 1291 jl138328 break; 1320 1291 jl138328 case K_GATEWAY: 1321 1291 jl138328 if (!NEXTTOKEN) { 1322 1291 jl138328 syntax_arg_missing(keyword_str); 1323 1291 jl138328 return (B_FALSE); 1324 1291 jl138328 } 1325 1291 jl138328 if (!getaddr(rcip, RTA_GATEWAY, tok, atype)) { 1326 1291 jl138328 return (B_FALSE); 1327 1291 jl138328 } 1328 1291 jl138328 break; 1329 1291 jl138328 case K_DST: 1330 1291 jl138328 if (!NEXTTOKEN) { 1331 1291 jl138328 syntax_arg_missing(keyword_str); 1332 1291 jl138328 return (B_FALSE); 1333 1291 jl138328 } 1334 1291 jl138328 if (!getaddr(rcip, RTA_DST, tok, atype)) { 1335 1291 jl138328 return (B_FALSE); 1336 1291 jl138328 } 1337 1291 jl138328 break; 1338 1291 jl138328 case K_NETMASK: 1339 1291 jl138328 if (!NEXTTOKEN) { 1340 1291 jl138328 syntax_arg_missing(keyword_str); 1341 1291 jl138328 return (B_FALSE); 1342 1291 jl138328 } 1343 1291 jl138328 if (!getaddr(rcip, RTA_NETMASK, tok, atype)) { 1344 1291 jl138328 return (B_FALSE); 1345 1291 jl138328 } 1346 1291 jl138328 atype = ADDR_TYPE_NET; 1347 1291 jl138328 break; 1348 1291 jl138328 case K_MTU: 1349 1291 jl138328 case K_HOPCOUNT: 1350 1291 jl138328 case K_EXPIRE: 1351 1291 jl138328 case K_RECVPIPE: 1352 1291 jl138328 case K_SENDPIPE: 1353 1291 jl138328 case K_SSTHRESH: 1354 1291 jl138328 case K_RTT: 1355 1291 jl138328 case K_RTTVAR: 1356 1291 jl138328 if (!NEXTTOKEN) { 1357 1291 jl138328 syntax_arg_missing(keyword_str); 1358 1291 jl138328 return (B_FALSE); 1359 1291 jl138328 } 1360 1291 jl138328 set_metric(rcip, tok, key, locknext || lockrest); 1361 1291 jl138328 locknext = B_FALSE; 1362 1291 jl138328 break; 1363 1291 jl138328 case K_PRIVATE: 1364 1291 jl138328 rcip->ri_flags |= RTF_PRIVATE; 1365 1291 jl138328 break; 1366 1291 jl138328 case K_MULTIRT: 1367 1291 jl138328 rcip->ri_flags |= RTF_MULTIRT; 1368 1291 jl138328 break; 1369 1291 jl138328 case K_SETSRC: 1370 1291 jl138328 if (!NEXTTOKEN) { 1371 1291 jl138328 syntax_arg_missing(keyword_str); 1372 1291 jl138328 return (B_FALSE); 1373 1291 jl138328 } 1374 1291 jl138328 if (!getaddr(rcip, RTA_SRC, tok, atype)) { 1375 1291 jl138328 return (B_FALSE); 1376 1291 jl138328 } 1377 1291 jl138328 rcip->ri_flags |= RTF_SETSRC; 1378 1676 jpk break; 1379 1676 jpk case K_SECATTR: 1380 1676 jpk if (!NEXTTOKEN) { 1381 1676 jpk syntax_arg_missing(keyword_str); 1382 1676 jpk return (B_FALSE); 1383 1676 jpk } 1384 2304 wy83408 if (is_system_labeled()) { 1385 1676 jpk int err; 1386 1676 jpk 1387 2304 wy83408 if (rcip->ri_rtsa_cnt >= 1) { 1388 2304 wy83408 syntax_error(gettext("route: can't " 1389 2304 wy83408 "specify more than one security " 1390 2304 wy83408 "attribute\n")); 1391 2304 wy83408 return (B_FALSE); 1392 2304 wy83408 } 1393 1676 jpk if (!rtsa_keyword(tok, &rcip->ri_rtsa, &err, 1394 1676 jpk NULL)) { 1395 2304 wy83408 syntax_error(gettext("route: " 1396 1676 jpk "bad security attribute: %s\n"), 1397 1676 jpk tsol_strerror(err, errno)); 1398 1676 jpk return (B_FALSE); 1399 1676 jpk } 1400 2304 wy83408 rcip->ri_rtsa_cnt++; 1401 2304 wy83408 } else { 1402 2304 wy83408 syntax_error(gettext("route: " 1403 2601 wy83408 "system is not labeled; cannot specify " 1404 2304 wy83408 "security attributes.\n")); 1405 1676 jpk return (B_FALSE); 1406 1676 jpk } 1407 1291 jl138328 break; 1408 11042 Erik case K_INDIRECT: 1409 11042 Erik rcip->ri_flags |= RTF_INDIRECT; 1410 11042 Erik break; 1411 1291 jl138328 default: 1412 1291 jl138328 if (dash_keyword) { 1413 1291 jl138328 syntax_bad_keyword(tok + 1); 1414 1291 jl138328 return (B_FALSE); 1415 1291 jl138328 } 1416 1291 jl138328 if ((rcip->ri_addrs & RTA_DST) == 0) { 1417 1291 jl138328 if (!getaddr(rcip, RTA_DST, tok, atype)) { 1418 1291 jl138328 return (B_FALSE); 1419 1291 jl138328 } 1420 1291 jl138328 } else if ((rcip->ri_addrs & RTA_GATEWAY) == 0) { 1421 0 stevel /* 1422 0 stevel * For the gateway parameter, retrieve the 1423 0 stevel * pointer to the struct hostent so that all 1424 0 stevel * possible addresses can be tried until one 1425 0 stevel * is successful. 1426 0 stevel */ 1427 1291 jl138328 if (!getaddr(rcip, RTA_GATEWAY, tok, atype)) { 1428 1291 jl138328 return (B_FALSE); 1429 1291 jl138328 } 1430 0 stevel } else { 1431 1291 jl138328 ulong_t metric; 1432 0 stevel /* 1433 0 stevel * Assume that a regular number is a metric. 1434 0 stevel * Needed for compatibility with old route 1435 0 stevel * command syntax. 1436 0 stevel */ 1437 1291 jl138328 errno = 0; 1438 1291 jl138328 metric = strtoul(tok, &err, 10); 1439 1291 jl138328 if (errno == 0 && *err == '\0' && 1440 0 stevel metric < 0x80000000ul) { 1441 0 stevel iflag = (metric == 0); 1442 0 stevel if (verbose) { 1443 0 stevel (void) printf("old usage of " 1444 0 stevel "trailing number, assuming " 1445 0 stevel "route %s\n", iflag ? 1446 0 stevel "to if" : "via gateway"); 1447 0 stevel } 1448 0 stevel continue; 1449 0 stevel } 1450 1291 jl138328 if (!getaddr(rcip, RTA_NETMASK, tok, atype)) { 1451 1291 jl138328 return (B_FALSE); 1452 1291 jl138328 } 1453 0 stevel } 1454 0 stevel } 1455 0 stevel } 1456 1291 jl138328 #undef NEXTTOKEN 1457 1291 jl138328 1458 1291 jl138328 if ((rcip->ri_addrs & RTA_DST) == 0) { 1459 1291 jl138328 syntax_error(gettext("route: destination required\n")); 1460 1291 jl138328 return (B_FALSE); 1461 1291 jl138328 } else if ((rcip->ri_cmd == RTM_ADD || rcip->ri_cmd == RTM_DELETE) && 1462 1291 jl138328 (rcip->ri_addrs & RTA_GATEWAY) == 0) { 1463 1291 jl138328 syntax_error(gettext( 1464 1291 jl138328 "route: gateway required for add or delete command\n")); 1465 1291 jl138328 return (B_FALSE); 1466 1291 jl138328 } 1467 1291 jl138328 1468 1291 jl138328 if (!iflag) { 1469 1291 jl138328 rcip->ri_flags |= RTF_GATEWAY; 1470 1291 jl138328 } 1471 1291 jl138328 1472 1291 jl138328 if (atype != ADDR_TYPE_NET) { 1473 1291 jl138328 if (rcip->ri_addrs & RTA_NETMASK) { 1474 1291 jl138328 /* 1475 1291 jl138328 * We know the netmask, so we can set the host flag 1476 1291 jl138328 * based on whether the netmask is the host netmask. 1477 1291 jl138328 */ 1478 1291 jl138328 if (rcip->ri_af == AF_INET && 1479 1291 jl138328 rcip->ri_mask.sin.sin_addr.s_addr == 1480 1291 jl138328 IP_HOST_MASK) { 1481 1291 jl138328 rcip->ri_flags |= RTF_HOST; 1482 1291 jl138328 } 1483 1291 jl138328 if (rcip->ri_af == AF_INET6 && 1484 1291 jl138328 memcmp(&rcip->ri_mask.sin6.sin6_addr, 1485 11042 Erik &in6_host_mask, 1486 11042 Erik sizeof (struct in6_addr)) == 0) { 1487 1291 jl138328 rcip->ri_flags |= RTF_HOST; 1488 1291 jl138328 } 1489 1291 jl138328 } else { 1490 1291 jl138328 /* 1491 1291 jl138328 * If no prefix mask has been saved at this point, it 1492 1291 jl138328 * only makes sense to treat the destination address 1493 1291 jl138328 * as a host address. 1494 1291 jl138328 */ 1495 1291 jl138328 rcip->ri_flags |= RTF_HOST; 1496 1291 jl138328 } 1497 1291 jl138328 } 1498 1291 jl138328 return (B_TRUE); 1499 1291 jl138328 } 1500 1291 jl138328 1501 1291 jl138328 /* 1502 1291 jl138328 * This command always seeks to the end of the file prior to writing. 1503 1291 jl138328 */ 1504 1291 jl138328 void 1505 1291 jl138328 write_to_rtfile(FILE *fp, int argc, char **argv) 1506 1291 jl138328 { 1507 1291 jl138328 char file_line[BUF_SIZE]; 1508 1291 jl138328 int len; 1509 1291 jl138328 int i; 1510 1291 jl138328 1511 1291 jl138328 len = 0; 1512 1291 jl138328 if (early_v6_keyword) { 1513 1291 jl138328 /* 1514 1291 jl138328 * This flag is set when "inet6" was seen as an 1515 1291 jl138328 * argument to the -f flag. Normally, when writing 1516 1291 jl138328 * routes to the persistent route file, everything on 1517 1291 jl138328 * the command line after "add" is saved verbatim. 1518 1291 jl138328 * In this case, the arguments after "add" may not be 1519 1291 jl138328 * sufficient, as the ipv6 keyword came before "add", 1520 1291 jl138328 * yet must be present in the persistent route file. 1521 1291 jl138328 */ 1522 1291 jl138328 len += snprintf(file_line, BUF_SIZE, "-inet6 "); 1523 1291 jl138328 } 1524 1291 jl138328 for (i = 0; argc > 0 && len < BUF_SIZE; i++, argc--) { 1525 1291 jl138328 len += snprintf(&file_line[len], BUF_SIZE - len, "%s ", 1526 1291 jl138328 argv[i]); 1527 1291 jl138328 } 1528 1291 jl138328 if (len >= BUF_SIZE) 1529 1291 jl138328 quit(gettext("Internal Error"), EINVAL); 1530 1291 jl138328 file_line[len - 1] = '\n'; 1531 1291 jl138328 if (fseek(fp, 0, SEEK_END) != 0 || 1532 1291 jl138328 fputs(file_line, fp) == EOF) { 1533 1291 jl138328 quit(gettext("failed to write to route file"), 1534 1291 jl138328 errno); 1535 1291 jl138328 } 1536 1291 jl138328 } 1537 1291 jl138328 1538 1291 jl138328 boolean_t 1539 1291 jl138328 compare_rtcmd(rtcmd_irep_t *srch_rt, rtcmd_irep_t *file_rt) 1540 1291 jl138328 { 1541 1291 jl138328 if (strcmp(srch_rt->ri_dest_str, file_rt->ri_dest_str) != 0 || 1542 1291 jl138328 memcmp(&srch_rt->ri_mask, &file_rt->ri_mask, sizeof (su_t)) != 0) { 1543 1291 jl138328 return (B_FALSE); 1544 1291 jl138328 } 1545 1291 jl138328 return (srch_rt->ri_gate_str == NULL || 1546 1291 jl138328 strcmp(srch_rt->ri_gate_str, file_rt->ri_gate_str) == 0); 1547 1291 jl138328 } 1548 1291 jl138328 1549 1291 jl138328 /* 1550 1291 jl138328 * Search the route file for routes matching the supplied route. There are 3 1551 1291 jl138328 * modes of operation: 1552 1291 jl138328 * SEARCH_MODE_RET - no side effects. 1553 1291 jl138328 * SEARCH_MODE_PRINT - prints each matching line. 1554 1291 jl138328 * SEARCH_MODE_DEL - copies all valid, non-matching lines to tmp_fp. 1555 1291 jl138328 * 1556 1291 jl138328 * In all cases, the number of matches is returned. If rt is NULL, all routes 1557 1291 jl138328 * matching the global af value are considered matching. 1558 1291 jl138328 */ 1559 1291 jl138328 int 1560 1291 jl138328 search_rtfile(FILE *fp, FILE *temp_fp, rtcmd_irep_t *rt, search_mode_t mode) 1561 1291 jl138328 { 1562 1291 jl138328 char *tmp_buf; 1563 1291 jl138328 int match_cnt; 1564 1291 jl138328 boolean_t match; 1565 1291 jl138328 char file_line[BUF_SIZE + 4] = "add "; 1566 1291 jl138328 rtcmd_irep_t *thisrt; 1567 1291 jl138328 1568 1291 jl138328 match_cnt = 0; 1569 1291 jl138328 1570 1291 jl138328 /* 1571 1291 jl138328 * Leave space at the beginning of file_line for "add ". 1572 1291 jl138328 */ 1573 1291 jl138328 while (fgets(file_line + 4, BUF_SIZE, fp) != NULL) { 1574 1291 jl138328 1575 1291 jl138328 if (file_line[4] == '#' || file_line[4] == '\n') { 1576 1291 jl138328 /* Handle comments and blank lines */ 1577 1291 jl138328 if (mode == SEARCH_MODE_DEL && 1578 1291 jl138328 fputs(file_line + 4, temp_fp) == EOF) { 1579 1291 jl138328 quit(gettext( 1580 1291 jl138328 "route: failed to write to temp file"), 1581 1291 jl138328 errno); 1582 1291 jl138328 } 1583 1291 jl138328 continue; 1584 1291 jl138328 } 1585 1291 jl138328 thisrt = new_rtcmd_irep(); 1586 1291 jl138328 /* 1587 1291 jl138328 * thisrt->ri_af defaults to whatever address family happens 1588 1291 jl138328 * to be set in the global af, but routes in the persistent 1589 1291 jl138328 * route file must be treated as AF_INET by default. 1590 1291 jl138328 */ 1591 1291 jl138328 thisrt->ri_af = AF_INET; 1592 1291 jl138328 1593 1291 jl138328 exit_on_error = B_FALSE; 1594 1291 jl138328 tmp_buf = strdup(file_line); 1595 1291 jl138328 /* args_to_rtcmd() will mangle the string passed. */ 1596 1291 jl138328 if (!args_to_rtcmd(thisrt, NULL, tmp_buf)) { 1597 1291 jl138328 /* There was an error in args_to_rtcmd() or helpers */ 1598 1291 jl138328 del_rtcmd_irep(thisrt); 1599 1291 jl138328 free(tmp_buf); 1600 1291 jl138328 continue; 1601 1291 jl138328 } 1602 1291 jl138328 exit_on_error = B_TRUE; 1603 1291 jl138328 free(tmp_buf); 1604 1291 jl138328 1605 1291 jl138328 if (thisrt->ri_gate_str == NULL) { 1606 1291 jl138328 del_rtcmd_irep(thisrt); 1607 1291 jl138328 continue; 1608 1291 jl138328 } 1609 1291 jl138328 match = (rt == NULL) ? (thisrt->ri_af == af) : 1610 1291 jl138328 compare_rtcmd(rt, thisrt); 1611 1291 jl138328 1612 1291 jl138328 if (match) match_cnt++; 1613 1291 jl138328 if (match && mode == SEARCH_MODE_PRINT) { 1614 1291 jl138328 (void) printf("persistent: route %s", file_line); 1615 1291 jl138328 } 1616 1291 jl138328 if (match && mode == SEARCH_MODE_DEL) { 1617 1291 jl138328 thisrt->ri_cmd = RTM_DELETE; 1618 1291 jl138328 print_rtcmd_short(stdout, thisrt, B_FALSE, B_TRUE); 1619 1291 jl138328 (void) printf("\n"); 1620 1291 jl138328 } 1621 1291 jl138328 del_rtcmd_irep(thisrt); 1622 1291 jl138328 1623 1291 jl138328 if (!match && mode == SEARCH_MODE_DEL && 1624 1291 jl138328 fputs(file_line + 4, temp_fp) == EOF) { 1625 1291 jl138328 quit(gettext("failed to write to temp file"), 1626 1291 jl138328 errno); 1627 1291 jl138328 } 1628 1291 jl138328 } 1629 1291 jl138328 return (match_cnt); 1630 1291 jl138328 } 1631 1291 jl138328 1632 1291 jl138328 /* 1633 1291 jl138328 * Perform the route operation given in argv on the persistent route file. 1634 1291 jl138328 * If do_flush is set, the persistent route file is flushed of all routes 1635 1291 jl138328 * matching the global family, and the arguments are ignored. 1636 1291 jl138328 */ 1637 1291 jl138328 void 1638 1291 jl138328 save_route(int argc, char **argv, int do_flush) 1639 1291 jl138328 { 1640 1291 jl138328 rtcmd_irep_t *rt; 1641 1291 jl138328 int perm_fd; 1642 1291 jl138328 FILE *perm_fp; 1643 1291 jl138328 FILE *temp_fp; 1644 1291 jl138328 mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 1645 1291 jl138328 struct flock lock; 1646 1291 jl138328 struct stat st; 1647 1291 jl138328 const char commentstr[] = 1648 1291 jl138328 "# File generated by route(1M) - do not edit.\n"; 1649 1291 jl138328 1650 1291 jl138328 perm_fd = open(perm_file, O_RDWR | O_CREAT, fmode); 1651 1291 jl138328 if (perm_fd == -1 || fstat(perm_fd, &st) == -1) 1652 1291 jl138328 quit("failed to open route file", errno); 1653 1291 jl138328 1654 1291 jl138328 lock.l_type = F_WRLCK; 1655 1291 jl138328 lock.l_whence = SEEK_SET; 1656 1291 jl138328 lock.l_start = 0; 1657 1291 jl138328 lock.l_len = 0; 1658 1291 jl138328 if (fcntl(perm_fd, F_SETLK, &lock) != 0) { 1659 1291 jl138328 quit(gettext("failed to lock route file"), errno); 1660 1291 jl138328 /* NOTREACHED */ 1661 1291 jl138328 } 1662 1291 jl138328 if (st.st_size == 0 && 1663 1291 jl138328 write(perm_fd, commentstr, sizeof (commentstr) - 1) != 1664 1291 jl138328 sizeof (commentstr) - 1) 1665 1291 jl138328 quit(gettext("failed to open route file"), errno); 1666 1291 jl138328 1667 1291 jl138328 if ((perm_fp = fdopen(perm_fd, "r+")) == NULL) { 1668 1291 jl138328 quit(gettext("failed to open route file"), errno); 1669 1291 jl138328 /* NOTREACHED */ 1670 1291 jl138328 } 1671 1291 jl138328 1672 1291 jl138328 if (!do_flush) { 1673 1291 jl138328 rt = new_rtcmd_irep(); 1674 1291 jl138328 (void) args_to_rtcmd(rt, argv, NULL); 1675 1291 jl138328 } 1676 1291 jl138328 if (do_flush || rt->ri_cmd == RTM_DELETE) { 1677 1291 jl138328 if ((temp_fp = fopen(temp_file, "w")) == NULL) { 1678 1291 jl138328 quit(gettext("failed to open temp file"), errno); 1679 1291 jl138328 /* NOTREACHED */ 1680 1291 jl138328 } 1681 1291 jl138328 } 1682 1291 jl138328 if (do_flush) { 1683 1291 jl138328 (void) search_rtfile(perm_fp, temp_fp, NULL, SEARCH_MODE_DEL); 1684 1291 jl138328 if (fclose(temp_fp) != 0 || rename(temp_file, perm_file) != 0) { 1685 1291 jl138328 quit(gettext("failed to update route file"), errno); 1686 1291 jl138328 /* NOTREACHED */ 1687 1291 jl138328 } 1688 1291 jl138328 (void) fclose(perm_fp); 1689 1291 jl138328 return; 1690 1291 jl138328 } 1691 1291 jl138328 1692 1291 jl138328 switch (rt->ri_cmd) { 1693 1291 jl138328 case RTM_ADD: 1694 1291 jl138328 if (search_rtfile(perm_fp, NULL, rt, SEARCH_MODE_NULL) > 0) { 1695 1291 jl138328 /* Route is already in the file */ 1696 1291 jl138328 print_rtcmd_short(stderr, rt, B_FALSE, B_TRUE); 1697 1291 jl138328 (void) fprintf(stderr, ": entry exists\n"); 1698 1291 jl138328 exit(1); 1699 1291 jl138328 } 1700 1291 jl138328 write_to_rtfile(perm_fp, argc - 1, argv + 1); 1701 1291 jl138328 print_rtcmd_short(stdout, rt, B_FALSE, B_TRUE); 1702 1291 jl138328 (void) printf("\n"); 1703 1291 jl138328 break; 1704 1291 jl138328 1705 1291 jl138328 case RTM_CHANGE: 1706 1291 jl138328 syntax_error( 1707 1291 jl138328 gettext("route: change command not supported with -p\n")); 1708 1291 jl138328 /* NOTREACHED */ 1709 1291 jl138328 1710 1291 jl138328 case RTM_DELETE: 1711 1291 jl138328 if (search_rtfile(perm_fp, temp_fp, rt, SEARCH_MODE_DEL) <= 0) { 1712 1291 jl138328 /* Route not found */ 1713 1291 jl138328 print_rtcmd_short(stderr, rt, B_FALSE, B_TRUE); 1714 1291 jl138328 (void) fprintf(stderr, gettext(": not in file\n")); 1715 1291 jl138328 exit(1); 1716 1291 jl138328 } 1717 1291 jl138328 if (fclose(temp_fp) != 0 || rename(temp_file, perm_file) != 0) { 1718 1291 jl138328 quit(gettext("failed to update route file"), errno); 1719 1291 jl138328 /* NOTREACHED */ 1720 1291 jl138328 } 1721 1291 jl138328 break; 1722 1291 jl138328 1723 1291 jl138328 case RTM_GET: 1724 1291 jl138328 if (search_rtfile(perm_fp, temp_fp, rt, SEARCH_MODE_PRINT) <= 1725 1291 jl138328 0) { 1726 1291 jl138328 print_rtcmd_short(stdout, rt, B_FALSE, B_TRUE); 1727 1291 jl138328 (void) printf(gettext(": not in file\n")); 1728 1291 jl138328 } 1729 1291 jl138328 break; 1730 1291 jl138328 1731 1291 jl138328 default: 1732 1291 jl138328 quit(gettext("Internal Error"), EINVAL); 1733 1291 jl138328 /* NOTREACHED */ 1734 0 stevel } 1735 0 stevel 1736 0 stevel /* 1737 1291 jl138328 * Closing the file unlocks it. 1738 0 stevel */ 1739 1291 jl138328 (void) fclose(perm_fp); 1740 1291 jl138328 } 1741 1291 jl138328 1742 1291 jl138328 int 1743 1291 jl138328 show_saved_routes(int argc) 1744 1291 jl138328 { 1745 1291 jl138328 int perm_fd; 1746 1291 jl138328 FILE *perm_fp; 1747 1291 jl138328 struct flock lock; 1748 1291 jl138328 int count = 0; 1749 1291 jl138328 1750 1291 jl138328 if (argc != 1) { 1751 1291 jl138328 syntax_error(gettext("route: invalid arguments for show\n")); 1752 0 stevel } 1753 1291 jl138328 1754 1291 jl138328 perm_fd = open(perm_file, O_RDONLY, 0); 1755 1291 jl138328 1756 1291 jl138328 if (perm_fd == -1) { 1757 1291 jl138328 if (errno == ENOENT) { 1758 1291 jl138328 (void) printf("No persistent routes are defined\n"); 1759 1291 jl138328 return (0); 1760 1291 jl138328 } else { 1761 1291 jl138328 quit(gettext("failed to open route file"), errno); 1762 1291 jl138328 } 1763 1291 jl138328 } 1764 1291 jl138328 lock.l_type = F_RDLCK; 1765 1291 jl138328 lock.l_whence = SEEK_SET; 1766 1291 jl138328 lock.l_start = 0; 1767 1291 jl138328 lock.l_len = 0; 1768 1291 jl138328 if (fcntl(perm_fd, F_SETLK, &lock) != 0) { 1769 1291 jl138328 quit(gettext("failed to lock route file"), 1770 1291 jl138328 errno); 1771 1291 jl138328 /* NOTREACHED */ 1772 1291 jl138328 } 1773 1291 jl138328 if ((perm_fp = fdopen(perm_fd, "r")) == NULL) { 1774 1291 jl138328 quit(gettext("failed to open route file"), errno); 1775 1291 jl138328 /* NOTREACHED */ 1776 1291 jl138328 } 1777 1291 jl138328 count += search_rtfile(perm_fp, NULL, NULL, SEARCH_MODE_PRINT); 1778 1291 jl138328 (void) fseek(perm_fp, 0, SEEK_SET); 1779 1291 jl138328 af = AF_INET6; 1780 1291 jl138328 count += search_rtfile(perm_fp, NULL, NULL, SEARCH_MODE_PRINT); 1781 1291 jl138328 1782 1291 jl138328 if (count == 0) 1783 1291 jl138328 (void) printf("No persistent routes are defined\n"); 1784 1291 jl138328 1785 1291 jl138328 (void) fclose(perm_fp); 1786 1291 jl138328 return (0); 1787 1291 jl138328 } 1788 1291 jl138328 1789 1291 jl138328 int 1790 1291 jl138328 newroute(char **argv) 1791 1291 jl138328 { 1792 1291 jl138328 rtcmd_irep_t *newrt; 1793 1291 jl138328 int ret, attempts, oerrno; 1794 1291 jl138328 char *err; 1795 1291 jl138328 char obuf[INET6_ADDRSTRLEN]; 1796 1291 jl138328 #define hp (newrt->ri_gate_hp) 1797 1291 jl138328 1798 1291 jl138328 newrt = new_rtcmd_irep(); 1799 1291 jl138328 (void) args_to_rtcmd(newrt, argv, NULL); 1800 1291 jl138328 1801 1291 jl138328 if (newrt->ri_cmd != RTM_GET && !tflag) { 1802 1291 jl138328 /* Don't want to read back our messages */ 1803 1291 jl138328 (void) shutdown(s, 0); 1804 1291 jl138328 } 1805 1291 jl138328 if (newrt->ri_addrs & RTA_IFP) { 1806 1291 jl138328 newrt->ri_ifp.sdl.sdl_index = if_nametoindex(newrt->ri_ifp_str); 1807 1291 jl138328 if (newrt->ri_ifp.sdl.sdl_index == 0) { 1808 1291 jl138328 if (errno != ENXIO) { 1809 1291 jl138328 quit("if_nametoindex", errno); 1810 1291 jl138328 } else { 1811 1291 jl138328 (void) fprintf(stderr, 1812 1291 jl138328 gettext("route: %s: no such interface\n"), 1813 1291 jl138328 newrt->ri_ifp_str); 1814 1291 jl138328 exit(1); 1815 1291 jl138328 } 1816 1291 jl138328 } 1817 1291 jl138328 newrt->ri_ifp.sdl.sdl_family = AF_LINK; 1818 1291 jl138328 } 1819 0 stevel for (attempts = 1; ; attempts++) { 1820 0 stevel errno = 0; 1821 1291 jl138328 if ((ret = rtmsg(newrt)) == 0) 1822 0 stevel break; 1823 0 stevel if (errno != ENETUNREACH && errno != ESRCH) 1824 0 stevel break; 1825 1291 jl138328 if ((newrt->ri_addrs & RTA_GATEWAY) && hp != NULL && 1826 0 stevel hp->h_addr_list[attempts] != NULL) { 1827 0 stevel switch (af) { 1828 0 stevel case AF_INET: 1829 1291 jl138328 (void) memmove(&newrt->ri_gate.sin.sin_addr, 1830 0 stevel hp->h_addr_list[attempts], hp->h_length); 1831 0 stevel continue; 1832 0 stevel case AF_INET6: 1833 1291 jl138328 (void) memmove(&newrt->ri_gate.sin6.sin6_addr, 1834 0 stevel hp->h_addr_list[attempts], hp->h_length); 1835 0 stevel continue; 1836 0 stevel } 1837 0 stevel } 1838 0 stevel break; 1839 0 stevel } 1840 0 stevel oerrno = errno; 1841 1291 jl138328 1842 1291 jl138328 if (newrt->ri_cmd != RTM_GET) { 1843 1291 jl138328 print_rtcmd_short(stdout, newrt, (ret == 0), B_FALSE); 1844 1291 jl138328 if (ret == 0) 1845 1291 jl138328 (void) printf("\n"); 1846 1291 jl138328 } else if (ret != 0) { 1847 1291 jl138328 /* 1848 1291 jl138328 * Note: there is nothing additional to print for get 1849 1291 jl138328 * if ret == 0. 1850 1291 jl138328 */ 1851 1291 jl138328 if (nflag) { 1852 1291 jl138328 switch (newrt->ri_af) { 1853 0 stevel case AF_INET: 1854 1291 jl138328 (void) printf(" %s", 1855 1291 jl138328 inet_ntoa(newrt->ri_dst.sin.sin_addr)); 1856 0 stevel break; 1857 0 stevel case AF_INET6: 1858 0 stevel if (inet_ntop(AF_INET6, 1859 11042 Erik (void *)&newrt->ri_dst.sin6.sin6_addr, 1860 11042 Erik obuf, INET6_ADDRSTRLEN) != NULL) { 1861 1291 jl138328 (void) printf(" %s", obuf); 1862 0 stevel break; 1863 0 stevel } 1864 0 stevel /* FALLTHROUGH */ 1865 0 stevel default: 1866 1291 jl138328 (void) printf("%s", newrt->ri_dest_str); 1867 0 stevel break; 1868 0 stevel } 1869 1291 jl138328 } else { 1870 1291 jl138328 (void) printf("%s", newrt->ri_dest_str); 1871 0 stevel } 1872 0 stevel } 1873 1291 jl138328 1874 0 stevel if (ret != 0) { 1875 0 stevel switch (oerrno) { 1876 0 stevel case ESRCH: 1877 0 stevel err = "not in table"; 1878 0 stevel break; 1879 0 stevel case EBUSY: 1880 0 stevel err = "entry in use"; 1881 0 stevel break; 1882 0 stevel case ENOBUFS: 1883 0 stevel err = "routing table overflow"; 1884 0 stevel break; 1885 0 stevel case EEXIST: 1886 0 stevel err = "entry exists"; 1887 0 stevel break; 1888 0 stevel case EPERM: 1889 0 stevel err = "insufficient privileges"; 1890 0 stevel break; 1891 0 stevel default: 1892 0 stevel err = strerror(oerrno); 1893 0 stevel break; 1894 0 stevel } 1895 0 stevel (void) printf(": %s\n", err); 1896 0 stevel } 1897 1291 jl138328 1898 1291 jl138328 del_rtcmd_irep(newrt); 1899 0 stevel 1900 0 stevel return (oerrno); 1901 1291 jl138328 #undef hp 1902 0 stevel } 1903 0 stevel 1904 0 stevel 1905 0 stevel /* 1906 0 stevel * Convert a network number to the corresponding IP address. 1907 0 stevel * If the RTA_NETMASK hasn't been specified yet set it based 1908 0 stevel * on the class of address. 1909 0 stevel */ 1910 0 stevel static void 1911 1291 jl138328 inet_makenetandmask(rtcmd_irep_t *rcip, in_addr_t net, struct sockaddr_in *sin) 1912 0 stevel { 1913 0 stevel in_addr_t addr, mask; 1914 0 stevel 1915 0 stevel if (net == 0) { 1916 0 stevel mask = addr = 0; 1917 0 stevel } else if (net < 128) { 1918 0 stevel addr = net << IN_CLASSA_NSHIFT; 1919 0 stevel mask = IN_CLASSA_NET; 1920 0 stevel } else if (net < 65536) { 1921 0 stevel addr = net << IN_CLASSB_NSHIFT; 1922 0 stevel mask = IN_CLASSB_NET; 1923 0 stevel } else if (net < 16777216L) { 1924 0 stevel addr = net << IN_CLASSC_NSHIFT; 1925 0 stevel mask = IN_CLASSC_NET; 1926 0 stevel } else { 1927 0 stevel addr = net; 1928 0 stevel if ((addr & IN_CLASSA_HOST) == 0) 1929 0 stevel mask = IN_CLASSA_NET; 1930 0 stevel else if ((addr & IN_CLASSB_HOST) == 0) 1931 0 stevel mask = IN_CLASSB_NET; 1932 0 stevel else if ((addr & IN_CLASSC_HOST) == 0) 1933 0 stevel mask = IN_CLASSC_NET; 1934 0 stevel else { 1935 0 stevel if (IN_CLASSA(addr)) 1936 0 stevel mask = IN_CLASSA_NET; 1937 0 stevel else if (IN_CLASSB(addr)) 1938 0 stevel mask = IN_CLASSB_NET; 1939 0 stevel else if (IN_CLASSC(addr)) 1940 0 stevel mask = IN_CLASSC_NET; 1941 0 stevel else 1942 0 stevel mask = IP_HOST_MASK; 1943 0 stevel mask = inet_makesubnetmask(addr, mask); 1944 0 stevel } 1945 0 stevel } 1946 0 stevel sin->sin_addr.s_addr = htonl(addr); 1947 0 stevel 1948 5577 sangeeta /* Class E default mask is 32 */ 1949 5577 sangeeta if (IN_CLASSE(addr)) 1950 5577 sangeeta mask = IN_CLASSE_NET; 1951 5577 sangeeta 1952 1291 jl138328 if (!(rcip->ri_addrs & RTA_NETMASK)) { 1953 1291 jl138328 rcip->ri_addrs |= RTA_NETMASK; 1954 1291 jl138328 sin = &rcip->ri_mask.sin; 1955 0 stevel sin->sin_addr.s_addr = htonl(mask); 1956 0 stevel sin->sin_family = AF_INET; 1957 0 stevel } 1958 0 stevel } 1959 0 stevel 1960 0 stevel static in_addr_t 1961 0 stevel inet_makesubnetmask(in_addr_t addr, in_addr_t mask) 1962 0 stevel { 1963 0 stevel int n; 1964 0 stevel struct ifconf ifc; 1965 0 stevel struct ifreq ifreq; 1966 0 stevel struct ifreq *ifr; 1967 0 stevel struct sockaddr_in *sin; 1968 0 stevel char *buf; 1969 0 stevel int numifs; 1970 0 stevel size_t bufsize; 1971 0 stevel int iosoc; 1972 0 stevel in_addr_t if_addr, if_mask; 1973 0 stevel in_addr_t if_subnetmask = 0; 1974 0 stevel short if_flags; 1975 0 stevel 1976 0 stevel if (mask == 0) 1977 0 stevel return (0); 1978 0 stevel if ((iosoc = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1979 0 stevel quit("socket", errno); 1980 0 stevel if (ioctl(iosoc, SIOCGIFNUM, (char *)&numifs) < 0) 1981 0 stevel quit("ioctl", errno); 1982 0 stevel bufsize = numifs * sizeof (struct ifreq); 1983 0 stevel buf = malloc(bufsize); 1984 0 stevel if (buf == NULL) 1985 0 stevel quit("malloc", errno); 1986 0 stevel (void) memset(&ifc, 0, sizeof (ifc)); 1987 0 stevel ifc.ifc_len = bufsize; 1988 0 stevel ifc.ifc_buf = buf; 1989 0 stevel if (ioctl(iosoc, SIOCGIFCONF, (char *)&ifc) < 0) 1990 0 stevel quit("ioctl (get interface configuration)", errno); 1991 0 stevel /* Let's check to see if this is maybe a local subnet route. */ 1992 0 stevel ifr = ifc.ifc_req; 1993 0 stevel for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { 1994 0 stevel ifreq = *ifr; 1995 0 stevel /* LINTED */ 1996 0 stevel sin = (struct sockaddr_in *)&ifr->ifr_addr; 1997 0 stevel if_addr = ntohl(sin->sin_addr.s_addr); 1998 0 stevel 1999 0 stevel if (ioctl(iosoc, SIOCGIFFLAGS, (char *)&ifreq) < 0) 2000 0 stevel quit("ioctl (get interface flags)", errno); 2001 0 stevel if ((ifreq.ifr_flags & IFF_UP) == 0) 2002 0 stevel continue; 2003 0 stevel if_flags = ifreq.ifr_flags; 2004 0 stevel 2005 0 stevel if (ioctl(iosoc, SIOCGIFNETMASK, (char *)&ifreq) < 0) 2006 0 stevel quit("ioctl (get netmask)", errno); 2007 0 stevel /* LINTED */ 2008 0 stevel sin = (struct sockaddr_in *)&ifreq.ifr_addr; 2009 0 stevel if_mask = ntohl(sin->sin_addr.s_addr); 2010 0 stevel if ((if_addr & mask) == (addr & mask)) { 2011 0 stevel /* 2012 0 stevel * Don't trust pt-pt interfaces if there are 2013 0 stevel * other interfaces. 2014 0 stevel */ 2015 0 stevel if (if_flags & IFF_POINTOPOINT) { 2016 0 stevel if_subnetmask = if_mask; 2017 0 stevel continue; 2018 0 stevel } 2019 0 stevel /* 2020 0 stevel * Fine. Just assume the same net mask as the 2021 0 stevel * directly attached subnet interface is using. 2022 0 stevel */ 2023 0 stevel return (if_mask); 2024 0 stevel } 2025 0 stevel } 2026 0 stevel if (if_subnetmask != 0) 2027 0 stevel return (if_subnetmask); 2028 0 stevel return (mask); 2029 0 stevel } 2030 0 stevel 2031 0 stevel /* 2032 1291 jl138328 * Interpret an argument as a network address of some kind. 2033 0 stevel * 2034 0 stevel * If the address family is one looked up in getaddr() using one of the 2035 0 stevel * getipnodebyX() functions (currently only AF_INET6), then callers should 2036 0 stevel * freehostent() the returned "struct hostent" pointer if one was passed in. 2037 1291 jl138328 * 2038 1291 jl138328 * If exit_on_error is true, this function will cause route to exit on error by 2039 1291 jl138328 * calling syntax_error(). Otherwise, it returns B_TRUE on success or B_FALSE 2040 1291 jl138328 * on failure. 2041 0 stevel */ 2042 0 stevel static boolean_t 2043 1291 jl138328 getaddr(rtcmd_irep_t *rcip, int which, char *s, addr_type_t atype) 2044 0 stevel { 2045 1291 jl138328 su_t *su; 2046 1291 jl138328 struct hostent **hpp; 2047 0 stevel struct hostent *hp; 2048 1291 jl138328 int masklen; 2049 0 stevel 2050 1291 jl138328 if (which == RTA_GATEWAY) { 2051 1291 jl138328 hpp = &(rcip->ri_gate_hp); 2052 1291 jl138328 } else { 2053 1291 jl138328 hpp = &hp; 2054 156 dduvall } 2055 0 stevel *hpp = NULL; 2056 1291 jl138328 2057 1291 jl138328 rcip->ri_addrs |= which; 2058 0 stevel switch (which) { 2059 0 stevel case RTA_DST: 2060 1291 jl138328 save_string(&rcip->ri_dest_str, s); 2061 1291 jl138328 su = &rcip->ri_dst; 2062 1291 jl138328 su->sa.sa_family = rcip->ri_af; 2063 0 stevel break; 2064 0 stevel case RTA_GATEWAY: 2065 1291 jl138328 save_string(&rcip->ri_gate_str, s); 2066 1291 jl138328 su = &rcip->ri_gate; 2067 1291 jl138328 su->sa.sa_family = rcip->ri_af; 2068 0 stevel break; 2069 0 stevel case RTA_NETMASK: 2070 1291 jl138328 su = &rcip->ri_mask; 2071 1291 jl138328 su->sa.sa_family = rcip->ri_af; 2072 0 stevel break; 2073 0 stevel case RTA_IFP: 2074 1291 jl138328 save_string(&rcip->ri_ifp_str, s); 2075 1291 jl138328 return (B_TRUE); 2076 0 stevel /* 2077 0 stevel * RTA_SRC has overloaded meaning. It can represent the 2078 0 stevel * src address of incoming or outgoing packets. 2079 0 stevel */ 2080 0 stevel case RTA_IFA: 2081 1291 jl138328 su = &rcip->ri_ifa; 2082 1291 jl138328 su->sa.sa_family = rcip->ri_af; 2083 0 stevel break; 2084 0 stevel case RTA_SRC: 2085 1291 jl138328 su = &rcip->ri_src; 2086 1291 jl138328 su->sa.sa_family = rcip->ri_af; 2087 0 stevel break; 2088 0 stevel default: 2089 0 stevel /* NOTREACHED */ 2090 0 stevel quit(gettext("Internal Error"), EINVAL); 2091 0 stevel /* NOTREACHED */ 2092 0 stevel } 2093 0 stevel if (strcmp(s, "default") == 0) { 2094 0 stevel if (which == RTA_DST) { 2095 1291 jl138328 return (getaddr(rcip, RTA_NETMASK, s, ADDR_TYPE_NET)); 2096 0 stevel } 2097 0 stevel if (which == RTA_SRC) { 2098 0 stevel return (B_TRUE); 2099 0 stevel } 2100 1291 jl138328 return (B_TRUE); 2101 0 stevel } 2102 1291 jl138328 switch (rcip->ri_af) { 2103 0 stevel case AF_LINK: 2104 0 stevel link_addr(s, &su->sdl); 2105 0 stevel return (B_TRUE); 2106 0 stevel case PF_ROUTE: 2107 0 stevel sockaddr(s, &su->sa); 2108 0 stevel return (B_TRUE); 2109 0 stevel case AF_INET6: 2110 0 stevel switch (which) { 2111 0 stevel case RTA_DST: 2112 1291 jl138328 if (!in6_getaddr(s, &su->sin6, &masklen, hpp)) { 2113 1291 jl138328 return (B_FALSE); 2114 0 stevel } 2115 1291 jl138328 if (masklen != NO_PREFIX) { 2116 1291 jl138328 (void) memset(&rcip->ri_mask.sin6.sin6_addr, 0, 2117 1291 jl138328 sizeof (rcip->ri_mask.sin6.sin6_addr)); 2118 156 dduvall if (!in_prefixlentomask(masklen, IPV6_ABITS, 2119 1291 jl138328 (uchar_t *)&rcip->ri_mask.sin6.sin6_addr)) { 2120 1291 jl138328 syntax_error(gettext( 2121 1291 jl138328 "route: bad prefix length: %d\n"), 2122 1291 jl138328 masklen); 2123 1291 jl138328 return (B_FALSE); 2124 0 stevel } 2125 1291 jl138328 rcip->ri_mask.sin6.sin6_family = rcip->ri_af; 2126 1291 jl138328 rcip->ri_addrs |= RTA_NETMASK; 2127 0 stevel } 2128 1291 jl138328 return (B_TRUE); 2129 0 stevel case RTA_GATEWAY: 2130 0 stevel case RTA_IFA: 2131 0 stevel case RTA_SRC: 2132 1291 jl138328 return (in6_getaddr(s, &su->sin6, NULL, hpp)); 2133 0 stevel case RTA_NETMASK: 2134 1291 jl138328 syntax_error( 2135 0 stevel gettext("route: -netmask not supported for IPv6: " 2136 1291 jl138328 "use <prefix>/<prefix-length> instead\n")); 2137 1291 jl138328 return (B_FALSE); 2138 0 stevel default: 2139 0 stevel quit(gettext("Internal Error"), EINVAL); 2140 0 stevel /* NOTREACHED */ 2141 0 stevel } 2142 0 stevel case AF_INET: 2143 0 stevel switch (which) { 2144 0 stevel case RTA_DST: 2145 1291 jl138328 if (!in_getaddr(s, &su->sin, &masklen, which, hpp, 2146 1291 jl138328 atype, rcip)) { 2147 1291 jl138328 return (B_FALSE); 2148 0 stevel } 2149 1291 jl138328 if (masklen != NO_PREFIX) { 2150 1291 jl138328 (void) memset(&rcip->ri_mask.sin.sin_addr, 0, 2151 1291 jl138328 sizeof (rcip->ri_mask.sin.sin_addr)); 2152 156 dduvall if (!in_prefixlentomask(masklen, IP_ABITS, 2153 1291 jl138328 (uchar_t *)&rcip->ri_mask.sin.sin_addr)) { 2154 1291 jl138328 syntax_error(gettext( 2155 1291 jl138328 "route: bad prefix length: %d\n"), 2156 1291 jl138328 masklen); 2157 1291 jl138328 return (B_FALSE); 2158 0 stevel } 2159 1291 jl138328 rcip->ri_mask.sin.sin_family = rcip->ri_af; 2160 1291 jl138328 rcip->ri_addrs |= RTA_NETMASK; 2161 0 stevel } 2162 1291 jl138328 return (B_TRUE); 2163 0 stevel case RTA_GATEWAY: 2164 0 stevel case RTA_IFA: 2165 0 stevel case RTA_NETMASK: 2166 0 stevel case RTA_SRC: 2167 1291 jl138328 return (in_getaddr(s, &su->sin, NULL, which, hpp, atype, 2168 1291 jl138328 rcip)); 2169 0 stevel default: 2170 0 stevel quit(gettext("Internal Error"), EINVAL); 2171 0 stevel /* NOTREACHED */ 2172 0 stevel } 2173 0 stevel default: 2174 0 stevel quit(gettext("Internal Error"), EINVAL); 2175 0 stevel /* NOTREACHED */ 2176 0 stevel } 2177 1291 jl138328 return (B_TRUE); 2178 0 stevel } 2179 0 stevel 2180 0 stevel /* 2181 0 stevel * Interpret an argument as an IPv4 network address of some kind, 2182 1291 jl138328 * returning B_TRUE on success or B_FALSE on failure. 2183 1291 jl138328 * This function will cause an exit() on failure if exit_on_failure is set. 2184 1291 jl138328 * 2185 1291 jl138328 * Note that this tries host interpretation before network interpretation, 2186 1291 jl138328 * except when -net has been given and the destination address is being parsed. 2187 0 stevel * 2188 0 stevel * If the plenp argument is non-NULL, allow <addr>/<n> syntax and 2189 0 stevel * pass out <n> in *plenp. 2190 0 stevel * If <n> doesn't parse return BAD_ADDR as *plenp. 2191 0 stevel * If no /<n> is present return NO_PREFIX as *plenp. 2192 0 stevel */ 2193 0 stevel static boolean_t 2194 0 stevel in_getaddr(char *s, struct sockaddr_in *sin, int *plenp, int which, 2195 1291 jl138328 struct hostent **hpp, addr_type_t atype, rtcmd_irep_t *rcip) 2196 0 stevel { 2197 0 stevel struct hostent *hp; 2198 0 stevel struct netent *np; 2199 0 stevel in_addr_t val; 2200 0 stevel char str[BUFSIZ]; 2201 0 stevel 2202 1291 jl138328 (void) strlcpy(str, s, sizeof (str)); 2203 0 stevel 2204 0 stevel /* 2205 1291 jl138328 * If plenp is non-NULL, /<n> syntax for netmask is allowed. 2206 0 stevel */ 2207 0 stevel if (plenp != NULL) { 2208 0 stevel char *cp; 2209 0 stevel 2210 0 stevel *plenp = in_getprefixlen(str, IP_ABITS); 2211 0 stevel if (*plenp == BAD_ADDR) 2212 0 stevel return (B_FALSE); 2213 0 stevel cp = strchr(str, '/'); 2214 0 stevel if (cp != NULL) 2215 0 stevel *cp = '\0'; 2216 0 stevel } else if (strchr(str, '/') != NULL) { 2217 1291 jl138328 syntax_error(gettext("route: %s: unexpected '/'\n"), str); 2218 1291 jl138328 return (B_FALSE); 2219 0 stevel } 2220 0 stevel 2221 0 stevel (void) memset(sin, 0, sizeof (*sin)); 2222 0 stevel sin->sin_family = AF_INET; 2223 0 stevel 2224 0 stevel /* 2225 1291 jl138328 * Handle 255.255.255.255 as a special case first. 2226 0 stevel */ 2227 1291 jl138328 if (strcmp(str, "255.255.255.255") == 0) { 2228 1291 jl138328 sin->sin_addr.s_addr = INADDR_BROADCAST; 2229 0 stevel return (B_TRUE); 2230 0 stevel } 2231 1291 jl138328 2232 1291 jl138328 val = inet_addr(str); 2233 1291 jl138328 if (val != (in_addr_t)-1) { 2234 1291 jl138328 /* Numeric address */ 2235 1291 jl138328 sin->sin_addr.s_addr = val; 2236 1291 jl138328 if (which == RTA_DST) { 2237 1291 jl138328 if (atype == ADDR_TYPE_NET || 2238 1291 jl138328 (atype == ADDR_TYPE_ANY && 2239 1291 jl138328 inet_lnaof(sin->sin_addr) == INADDR_ANY)) { 2240 1291 jl138328 /* This looks like a network address. */ 2241 1291 jl138328 inet_makenetandmask(rcip, ntohl(val), 2242 11042 Erik sin); 2243 1291 jl138328 } 2244 1291 jl138328 } 2245 1291 jl138328 return (B_TRUE); 2246 0 stevel } 2247 1291 jl138328 /* Host or net name */ 2248 1291 jl138328 if (which != RTA_DST || atype != ADDR_TYPE_NET) { 2249 1291 jl138328 /* A host name is allowed. */ 2250 1291 jl138328 if ((hp = gethostbyname(str)) != NULL) { 2251 1291 jl138328 *hpp = hp; 2252 1291 jl138328 (void) memmove(&sin->sin_addr, hp->h_addr, 2253 1291 jl138328 hp->h_length); 2254 1291 jl138328 return (B_TRUE); 2255 1291 jl138328 } 2256 1291 jl138328 } 2257 1291 jl138328 if (atype != ADDR_TYPE_HOST) { 2258 1291 jl138328 /* A network name is allowed */ 2259 1291 jl138328 if ((np = getnetbyname(str)) != NULL && 2260 1291 jl138328 (val = np->n_net) != 0) { 2261 1291 jl138328 if (which == RTA_DST) { 2262 1291 jl138328 inet_makenetandmask(rcip, val, sin); 2263 1291 jl138328 } 2264 1291 jl138328 return (B_TRUE); 2265 1291 jl138328 } 2266 1291 jl138328 } 2267 1291 jl138328 syntax_error(gettext("%s: bad value\n"), s); 2268 1291 jl138328 return (B_FALSE); 2269 0 stevel } 2270 0 stevel 2271 0 stevel /* 2272 0 stevel * Interpret an argument as an IPv6 network address of some kind, 2273 1291 jl138328 * returning B_TRUE on success or B_FALSE on failure. 2274 1291 jl138328 * This function will cause an exit() on failure if exit_on_failure is set. 2275 0 stevel * 2276 0 stevel * If the last argument is non-NULL allow a <addr>/<n> syntax and 2277 0 stevel * pass out <n> in *plenp. 2278 0 stevel * If <n> doesn't parse return BAD_ADDR as *plenp. 2279 0 stevel * If no /<n> is present return NO_PREFIX as *plenp. 2280 0 stevel */ 2281 0 stevel static boolean_t 2282 0 stevel in6_getaddr(char *s, struct sockaddr_in6 *sin6, int *plenp, 2283 0 stevel struct hostent **hpp) 2284 0 stevel { 2285 0 stevel struct hostent *hp; 2286 0 stevel char str[BUFSIZ]; 2287 0 stevel int error_num; 2288 0 stevel 2289 1291 jl138328 (void) strlcpy(str, s, sizeof (str)); 2290 0 stevel 2291 0 stevel /* 2292 1291 jl138328 * If plenp is non-NULL, /<n> syntax for netmask is allowed. 2293 0 stevel */ 2294 0 stevel if (plenp != NULL) { 2295 0 stevel char *cp; 2296 0 stevel 2297 0 stevel *plenp = in_getprefixlen(str, IPV6_ABITS); 2298 0 stevel if (*plenp == BAD_ADDR) 2299 0 stevel return (B_FALSE); 2300 0 stevel cp = strchr(str, '/'); 2301 0 stevel if (cp != NULL) 2302 0 stevel *cp = '\0'; 2303 0 stevel } else if (strchr(str, '/') != NULL) { 2304 1291 jl138328 syntax_error(gettext("route: %s: unexpected '/'\n"), str); 2305 1291 jl138328 return (B_FALSE); 2306 0 stevel } 2307 0 stevel 2308 0 stevel (void) memset(sin6, 0, sizeof (struct sockaddr_in6)); 2309 0 stevel sin6->sin6_family = AF_INET6; 2310 0 stevel 2311 0 stevel hp = getipnodebyname(str, AF_INET6, 0, &error_num); 2312 0 stevel if (hp != NULL) { 2313 0 stevel *hpp = hp; 2314 0 stevel (void) memmove(&sin6->sin6_addr, hp->h_addr, hp->h_length); 2315 0 stevel return (B_TRUE); 2316 0 stevel } 2317 0 stevel if (error_num == TRY_AGAIN) { 2318 1291 jl138328 /* 2319 1291 jl138328 * This isn't a problem if we aren't going to use the address 2320 1291 jl138328 * right away. 2321 1291 jl138328 */ 2322 1291 jl138328 if (!exit_on_error) { 2323 1291 jl138328 return (B_TRUE); 2324 1291 jl138328 } 2325 1291 jl138328 syntax_error(gettext("route: %s: bad address (try " 2326 0 stevel "again later)\n"), s); 2327 1291 jl138328 return (B_FALSE); 2328 0 stevel } 2329 1291 jl138328 syntax_error(gettext("route: %s: bad address\n"), s); 2330 1291 jl138328 return (B_FALSE); 2331 0 stevel } 2332 0 stevel 2333 0 stevel /* 2334 1291 jl138328 * Parse <addr>/<n> syntax and return the integer n. 2335 1291 jl138328 * If <addr> is missing or <n> is not a valid integer, this function calls 2336 1291 jl138328 * syntax_error() and returns BAD_ADDR. 2337 1291 jl138328 * if n is not between 0 and max_plen inclusive, this functions calls 2338 1291 jl138328 * syntax_error() and returns BAD_ADDR. 2339 1291 jl138328 * If /<n> is not present, this function returns NO_PREFIX. 2340 1291 jl138328 * The string addr is not modified. 2341 0 stevel */ 2342 0 stevel int 2343 0 stevel in_getprefixlen(char *addr, int max_plen) 2344 0 stevel { 2345 0 stevel int prefixlen; 2346 0 stevel char *str, *end; 2347 0 stevel 2348 0 stevel str = strchr(addr, '/'); 2349 1291 jl138328 if (str == addr) { 2350 1291 jl138328 syntax_error(gettext("route: %s: unexpected '/'\n"), addr); 2351 1291 jl138328 return (BAD_ADDR); 2352 1291 jl138328 } 2353 0 stevel if (str == NULL) 2354 0 stevel return (NO_PREFIX); 2355 0 stevel str++; 2356 0 stevel 2357 1291 jl138328 errno = 0; 2358 1291 jl138328 prefixlen = strtoul(str, &end, 10); 2359 1291 jl138328 if (errno != 0 || str == end) { 2360 1291 jl138328 syntax_error(gettext("route: bad prefix length %s\n"), str); 2361 0 stevel return (BAD_ADDR); 2362 1291 jl138328 } 2363 1291 jl138328 if (prefixlen > max_plen) { 2364 1291 jl138328 syntax_error(gettext("route: prefix length %s out of range\n"), 2365 1291 jl138328 str); 2366 0 stevel return (BAD_ADDR); 2367 1291 jl138328 } 2368 1291 jl138328 return (prefixlen); 2369 0 stevel } 2370 0 stevel 2371 0 stevel /* 2372 0 stevel * Convert a prefix length to a mask. 2373 0 stevel * Returns B_TRUE if ok. B_FALSE otherwise. 2374 0 stevel * Assumes the mask array is zeroed by the caller. 2375 0 stevel */ 2376 0 stevel boolean_t 2377 0 stevel in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 2378 0 stevel { 2379 0 stevel if (prefixlen < 0 || prefixlen > maxlen) 2380 0 stevel return (B_FALSE); 2381 0 stevel 2382 0 stevel while (prefixlen > 0) { 2383 0 stevel if (prefixlen >= 8) { 2384 0 stevel *mask++ = 0xFF; 2385 0 stevel prefixlen -= 8; 2386 0 stevel continue; 2387 0 stevel } 2388 0 stevel *mask |= 1 << (8 - prefixlen); 2389 0 stevel prefixlen--; 2390 0 stevel } 2391 0 stevel return (B_TRUE); 2392 0 stevel } 2393 0 stevel 2394 0 stevel void 2395 0 stevel rtmonitor(int argc, char *argv[]) 2396 0 stevel { 2397 0 stevel int n; 2398 0 stevel intmax_t msg[2048 / sizeof (intmax_t)]; 2399 0 stevel 2400 0 stevel if (tflag) 2401 0 stevel exit(0); 2402 0 stevel verbose = B_TRUE; 2403 0 stevel if (argc > 1) { 2404 0 stevel argv++; 2405 0 stevel if (argc == 2 && **argv == '-') { 2406 0 stevel switch (keyword(*argv + 1)) { 2407 0 stevel case K_INET: 2408 0 stevel af = AF_INET; 2409 0 stevel break; 2410 0 stevel case K_LINK: 2411 0 stevel af = AF_LINK; 2412 0 stevel break; 2413 0 stevel case K_INET6: 2414 0 stevel af = AF_INET6; 2415 0 stevel break; 2416 0 stevel default: 2417 0 stevel usage(*argv); 2418 0 stevel /* NOTREACHED */ 2419 0 stevel } 2420 0 stevel } else { 2421 0 stevel usage(*argv); 2422 0 stevel } 2423 0 stevel (void) close(s); 2424 0 stevel s = socket(PF_ROUTE, SOCK_RAW, af); 2425 0 stevel if (s < 0) 2426 0 stevel quit("socket", errno); 2427 0 stevel } 2428 0 stevel for (;;) { 2429 0 stevel n = read(s, msg, sizeof (msg)); 2430 0 stevel if (n <= 0) 2431 0 stevel quit("read", errno); 2432 0 stevel (void) printf("got message of size %d\n", n); 2433 0 stevel print_rtmsg((struct rt_msghdr *)msg, n); 2434 0 stevel } 2435 0 stevel } 2436 0 stevel 2437 0 stevel int 2438 1291 jl138328 rtmsg(rtcmd_irep_t *newrt) 2439 0 stevel { 2440 0 stevel static int seq; 2441 0 stevel int rlen; 2442 0 stevel char *cp = m_rtmsg.m_space; 2443 0 stevel int l; 2444 0 stevel 2445 0 stevel errno = 0; 2446 0 stevel (void) memset(&m_rtmsg, 0, sizeof (m_rtmsg)); 2447 1291 jl138328 2448 1291 jl138328 if (newrt->ri_cmd == RTM_GET) { 2449 1291 jl138328 newrt->ri_ifp.sa.sa_family = AF_LINK; 2450 1291 jl138328 newrt->ri_addrs |= RTA_IFP; 2451 0 stevel } 2452 1291 jl138328 2453 0 stevel #define rtm m_rtmsg.m_rtm 2454 1291 jl138328 rtm.rtm_type = newrt->ri_cmd; 2455 1291 jl138328 rtm.rtm_flags = newrt->ri_flags; 2456 0 stevel rtm.rtm_version = RTM_VERSION; 2457 0 stevel rtm.rtm_seq = ++seq; 2458 1291 jl138328 rtm.rtm_addrs = newrt->ri_addrs; 2459 1291 jl138328 rtm.rtm_rmx = newrt->ri_metrics; 2460 1291 jl138328 rtm.rtm_inits = newrt->ri_inits; 2461 0 stevel 2462 0 stevel #define NEXTADDR(w, u) \ 2463 1291 jl138328 if (newrt->ri_addrs & (w)) { \ 2464 0 stevel l = ROUNDUP_LONG(salen(&u.sa)); \ 2465 0 stevel (void) memmove(cp, &(u), l); \ 2466 0 stevel cp += l; \ 2467 0 stevel if (verbose) \ 2468 0 stevel sodump(&(u), #u); \ 2469 0 stevel } 2470 1291 jl138328 NEXTADDR(RTA_DST, newrt->ri_dst); 2471 1291 jl138328 NEXTADDR(RTA_GATEWAY, newrt->ri_gate); 2472 1291 jl138328 NEXTADDR(RTA_NETMASK, newrt->ri_mask); 2473 1291 jl138328 NEXTADDR(RTA_IFP, newrt->ri_ifp); 2474 1291 jl138328 NEXTADDR(RTA_IFA, newrt->ri_ifa); 2475 0 stevel /* 2476 0 stevel * RTA_SRC has overloaded meaning. It can represent the 2477 0 stevel * src address of incoming or outgoing packets. 2478 0 stevel */ 2479 1291 jl138328 NEXTADDR(RTA_SRC, newrt->ri_src); 2480 0 stevel #undef NEXTADDR 2481 1676 jpk 2482 1676 jpk if (newrt->ri_rtsa_cnt > 0) { 2483 1676 jpk /* LINTED: aligned */ 2484 1676 jpk rtm_ext_t *rtm_ext = (rtm_ext_t *)cp; 2485 1676 jpk tsol_rtsecattr_t *rtsecattr; 2486 1676 jpk 2487 1676 jpk rtm_ext->rtmex_type = RTMEX_GATEWAY_SECATTR; 2488 1676 jpk rtm_ext->rtmex_len = TSOL_RTSECATTR_SIZE(1); 2489 1676 jpk 2490 1676 jpk rtsecattr = (tsol_rtsecattr_t *)(rtm_ext + 1); 2491 1676 jpk rtsecattr->rtsa_cnt = 1; 2492 1676 jpk 2493 1676 jpk bcopy(&newrt->ri_rtsa, rtsecattr->rtsa_attr, 2494 1676 jpk sizeof (newrt->ri_rtsa)); 2495 1676 jpk cp = (char *)(rtsecattr->rtsa_attr + 1); 2496 1676 jpk } 2497 1676 jpk 2498 0 stevel rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 2499 1676 jpk 2500 0 stevel if (verbose) 2501 0 stevel print_rtmsg(&rtm, l); 2502 0 stevel if (debugonly) 2503 0 stevel return (0); 2504 0 stevel if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 2505 0 stevel switch (errno) { 2506 0 stevel case ESRCH: 2507 0 stevel case EBUSY: 2508 0 stevel case ENOBUFS: 2509 0 stevel case EEXIST: 2510 0 stevel case ENETUNREACH: 2511 0 stevel case EHOSTUNREACH: 2512 0 stevel case EPERM: 2513 0 stevel break; 2514 0 stevel default: 2515 0 stevel perror(gettext("writing to routing socket")); 2516 0 stevel break; 2517 0 stevel } 2518 0 stevel return (-1); 2519 0 stevel } else if (rlen < (int)rtm.rtm_msglen) { 2520 0 stevel (void) fprintf(stderr, 2521 0 stevel gettext("route: write to routing socket got only %d for " 2522 0 stevel "len\n"), rlen); 2523 0 stevel return (-1); 2524 0 stevel } 2525 1291 jl138328 if (newrt->ri_cmd == RTM_GET) { 2526 0 stevel do { 2527 0 stevel l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg)); 2528 0 stevel } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 2529 0 stevel if (l < 0) { 2530 0 stevel (void) fprintf(stderr, 2531 0 stevel gettext("route: read from routing socket: %s\n"), 2532 0 stevel strerror(errno)); 2533 0 stevel } else { 2534 1291 jl138328 print_getmsg(newrt, &rtm, l); 2535 0 stevel } 2536 0 stevel } 2537 0 stevel #undef rtm 2538 0 stevel return (0); 2539 0 stevel } 2540 0 stevel 2541 0 stevel static char *msgtypes[] = { 2542 0 stevel "", 2543 0 stevel "RTM_ADD: Add Route", 2544 0 stevel "RTM_DELETE: Delete Route", 2545 0 stevel "RTM_CHANGE: Change Metrics or flags", 2546 0 stevel "RTM_GET: Report Metrics", 2547 0 stevel "RTM_LOSING: Kernel Suspects Partitioning", 2548 0 stevel "RTM_REDIRECT: Told to use different route", 2549 0 stevel "RTM_MISS: Lookup failed on this address", 2550 0 stevel "RTM_LOCK: fix specified metrics", 2551 0 stevel "RTM_OLDADD: caused by SIOCADDRT", 2552 0 stevel "RTM_OLDDEL: caused by SIOCDELRT", 2553 0 stevel "RTM_RESOLVE: Route created by cloning", 2554 11076 Cathy "RTM_NEWADDR: address being brought up on iface", 2555 11076 Cathy "RTM_DELADDR: address being brought down on iface", 2556 0 stevel "RTM_IFINFO: iface status change", 2557 11076 Cathy "RTM_CHGADDR: address being changed on iface", 2558 11076 Cathy "RTM_FREEADDR: address being removed from iface", 2559 0 stevel 0, 2560 0 stevel }; 2561 0 stevel 2562 0 stevel #define NMSGTYPES (sizeof (msgtypes) / sizeof (msgtypes[0])) 2563 0 stevel 2564 0 stevel static char metricnames[] = 2565 0 stevel "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount" 2566 0 stevel "\1mtu"; 2567 0 stevel static char routeflags[] = 2568 0 stevel "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT" 2569 0 stevel "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 2570 11042 Erik "\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC\023INDIRECT"; 2571 0 stevel static char ifnetflags[] = 2572 0 stevel "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP" 2573 0 stevel "\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST" 2574 0 stevel "\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE" 2575 0 stevel "\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF" 2576 0 stevel "\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6" 2577 4823 seb "\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE" 2578 4823 seb "\041XRESOLV\042COS\043PREFERRED\044TEMPORARY\045FIXEDMTU\046VIRTUAL" 2579 4823 seb "\047DUPLICATE"; 2580 0 stevel static char addrnames[] = 2581 0 stevel "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC"; 2582 0 stevel 2583 0 stevel void 2584 0 stevel print_rtmsg(struct rt_msghdr *rtm, int msglen) 2585 0 stevel { 2586 0 stevel struct if_msghdr *ifm; 2587 0 stevel struct ifa_msghdr *ifam; 2588 0 stevel 2589 0 stevel if (!verbose) 2590 0 stevel return; 2591 0 stevel if (rtm->rtm_version != RTM_VERSION) { 2592 0 stevel (void) printf("routing message version %d not understood\n", 2593 0 stevel rtm->rtm_version); 2594 0 stevel return; 2595 0 stevel } 2596 1676 jpk if (rtm->rtm_msglen != msglen) { 2597 0 stevel (void) printf("message length mismatch, in packet %d, " 2598 0 stevel "returned %d\n", 2599 0 stevel rtm->rtm_msglen, msglen); 2600 1676 jpk if (msglen > rtm->rtm_msglen) 2601 1676 jpk msglen = rtm->rtm_msglen; 2602 0 stevel } 2603 0 stevel /* 2604 0 stevel * Since rtm->rtm_type is unsigned, we'll just check the case of zero 2605 0 stevel * and the upper-bound of (NMSGTYPES - 1). 2606 0 stevel */ 2607 0 stevel if (rtm->rtm_type == 0 || rtm->rtm_type >= (NMSGTYPES - 1)) { 2608 0 stevel (void) printf("routing message type %d not understood\n", 2609 0 stevel rtm->rtm_type); 2610 0 stevel return; 2611 0 stevel } 2612 1676 jpk (void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], msglen); 2613 0 stevel switch (rtm->rtm_type) { 2614 0 stevel case RTM_IFINFO: 2615 0 stevel ifm = (struct if_msghdr *)rtm; 2616 0 stevel (void) printf("if# %d, flags:", ifm->ifm_index); 2617 0 stevel bprintf(stdout, ifm->ifm_flags, ifnetflags); 2618 1676 jpk pmsg_addrs((const char *)(ifm + 1), msglen - sizeof (*ifm), 2619 1676 jpk ifm->ifm_addrs); 2620 0 stevel break; 2621 0 stevel case RTM_NEWADDR: 2622 0 stevel case RTM_DELADDR: 2623 11076 Cathy case RTM_CHGADDR: 2624 11076 Cathy case RTM_FREEADDR: 2625 0 stevel ifam = (struct ifa_msghdr *)rtm; 2626 0 stevel (void) printf("metric %d, flags:", ifam->ifam_metric); 2627 0 stevel bprintf(stdout, ifam->ifam_flags, routeflags); 2628 1676 jpk pmsg_addrs((const char *)(ifam + 1), msglen - sizeof (*ifam), 2629 1676 jpk ifam->ifam_addrs); 2630 0 stevel break; 2631 0 stevel default: 2632 0 stevel (void) printf("pid: %ld, seq %d, errno %d, flags:", 2633 11042 Erik rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 2634 0 stevel bprintf(stdout, rtm->rtm_flags, routeflags); 2635 1676 jpk pmsg_common(rtm, msglen); 2636 1676 jpk break; 2637 0 stevel } 2638 0 stevel } 2639 0 stevel 2640 0 stevel void 2641 1291 jl138328 print_getmsg(rtcmd_irep_t *req_rt, struct rt_msghdr *rtm, int msglen) 2642 0 stevel { 2643 0 stevel struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL; 2644 0 stevel struct sockaddr_dl *ifp = NULL; 2645 0 stevel struct sockaddr *sa; 2646 0 stevel char *cp; 2647 0 stevel int i; 2648 0 stevel 2649 1291 jl138328 (void) printf(" route to: %s\n", routename(&req_rt->ri_dst.sa)); 2650 0 stevel if (rtm->rtm_version != RTM_VERSION) { 2651 0 stevel (void) fprintf(stderr, 2652 0 stevel gettext("routing message version %d not understood\n"), 2653 0 stevel rtm->rtm_version); 2654 0 stevel return; 2655 0 stevel } 2656 0 stevel if (rtm->rtm_msglen > (ushort_t)msglen) { 2657 0 stevel (void) fprintf(stderr, 2658 0 stevel gettext("message length mismatch, in packet %d, " 2659 11042 Erik "returned %d\n"), rtm->rtm_msglen, msglen); 2660 0 stevel } 2661 0 stevel if (rtm->rtm_errno) { 2662 0 stevel (void) fprintf(stderr, "RTM_GET: %s (errno %d)\n", 2663 0 stevel strerror(rtm->rtm_errno), rtm->rtm_errno); 2664 0 stevel return; 2665 0 stevel } 2666 0 stevel cp = ((char *)(rtm + 1)); 2667 0 stevel if (rtm->rtm_addrs != 0) { 2668 0 stevel for (i = 1; i != 0; i <<= 1) { 2669 0 stevel if (i & rtm->rtm_addrs) { 2670 0 stevel /* LINTED */ 2671 0 stevel sa = (struct sockaddr *)cp; 2672 0 stevel switch (i) { 2673 0 stevel case RTA_DST: 2674 0 stevel dst = sa; 2675 0 stevel break; 2676 0 stevel case RTA_GATEWAY: 2677 0 stevel gate = sa; 2678 0 stevel break; 2679 0 stevel case RTA_NETMASK: 2680 0 stevel mask = sa; 2681 0 stevel break; 2682 0 stevel case RTA_IFP: 2683 0 stevel if (sa->sa_family == AF_LINK && 2684 0 stevel ((struct sockaddr_dl *)sa)-> 2685 11042 Erik sdl_nlen != 0) 2686 0 stevel ifp = (struct sockaddr_dl *)sa; 2687 0 stevel break; 2688 0 stevel case RTA_SRC: 2689 0 stevel src = sa; 2690 0 stevel break; 2691 0 stevel } 2692 0 stevel ADVANCE(cp, sa); 2693 0 stevel } 2694 0 stevel } 2695 0 stevel } 2696 0 stevel if (dst != NULL && mask != NULL) 2697 0 stevel mask->sa_family = dst->sa_family; /* XXX */ 2698 0 stevel if (dst != NULL) 2699 0 stevel (void) printf("destination: %s\n", routename(dst)); 2700 0 stevel if (mask != NULL) { 2701 0 stevel boolean_t savenflag = nflag; 2702 0 stevel 2703 0 stevel nflag = B_TRUE; 2704 0 stevel (void) printf(" mask: %s\n", routename(mask)); 2705 0 stevel nflag = savenflag; 2706 0 stevel } 2707 0 stevel if (gate != NULL && rtm->rtm_flags & RTF_GATEWAY) 2708 0 stevel (void) printf(" gateway: %s\n", routename(gate)); 2709 0 stevel if (src != NULL && rtm->rtm_flags & RTF_SETSRC) 2710 0 stevel (void) printf(" setsrc: %s\n", routename(src)); 2711 0 stevel if (ifp != NULL) { 2712 0 stevel if (verbose) { 2713 0 stevel int i; 2714 0 stevel 2715 0 stevel (void) printf(" interface: %.*s index %d address ", 2716 0 stevel ifp->sdl_nlen, ifp->sdl_data, ifp->sdl_index); 2717 0 stevel for (i = ifp->sdl_nlen; 2718 0 stevel i < ifp->sdl_nlen + ifp->sdl_alen; 2719 0 stevel i++) { 2720 0 stevel (void) printf("%02x ", 2721 0 stevel ifp->sdl_data[i] & 0xFF); 2722 0 stevel } 2723 0 stevel (void) printf("\n"); 2724 0 stevel } else { 2725 0 stevel (void) printf(" interface: %.*s\n", 2726 0 stevel ifp->sdl_nlen, ifp->sdl_data); 2727 0 stevel } 2728 0 stevel } 2729 0 stevel (void) printf(" flags: "); 2730 0 stevel bprintf(stdout, rtm->rtm_flags, routeflags); 2731 0 stevel 2732 0 stevel #define lock(f) ((rtm->rtm_rmx.rmx_locks & RTV_ ## f) ? 'L' : ' ') 2733 0 stevel #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 2734 0 stevel 2735 0 stevel (void) printf("\n%s\n", " recvpipe sendpipe ssthresh rtt,ms " 2736 0 stevel "rttvar,ms hopcount mtu expire"); 2737 0 stevel (void) printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 2738 0 stevel (void) printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 2739 0 stevel (void) printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 2740 0 stevel (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 2741 0 stevel (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 2742 0 stevel (void) printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 2743 0 stevel (void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 2744 0 stevel if (rtm->rtm_rmx.rmx_expire) 2745 0 stevel rtm->rtm_rmx.rmx_expire -= time(0); 2746 1676 jpk (void) printf("%8d%c", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 2747 0 stevel #undef lock 2748 0 stevel #undef msec 2749 0 stevel #define RTA_IGN \ 2750 0 stevel (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC) 2751 0 stevel if (verbose) { 2752 1676 jpk pmsg_common(rtm, msglen); 2753 1676 jpk } else { 2754 1676 jpk const char *sptr, *endptr; 2755 1676 jpk const struct sockaddr *sa; 2756 1676 jpk uint_t addrs; 2757 1676 jpk 2758 1676 jpk /* Not verbose; just print out the exceptional cases */ 2759 1676 jpk if (rtm->rtm_addrs &~ RTA_IGN) { 2760 1676 jpk (void) printf("\nsockaddrs: "); 2761 1676 jpk bprintf(stdout, rtm->rtm_addrs, addrnames); 2762 1676 jpk } 2763 1676 jpk sptr = (const char *)(rtm + 1); 2764 1676 jpk endptr = (const char *)rtm + msglen; 2765 1676 jpk addrs = rtm->rtm_addrs; 2766 1676 jpk while (addrs != 0 && sptr + sizeof (*sa) <= endptr) { 2767 1676 jpk addrs &= addrs - 1; 2768 1676 jpk /* LINTED */ 2769 1676 jpk sa = (const struct sockaddr *)sptr; 2770 1676 jpk ADVANCE(sptr, sa); 2771 1676 jpk } 2772 1676 jpk if (addrs == 0) 2773 1676 jpk pmsg_secattr(sptr, endptr - sptr, " secattr: "); 2774 0 stevel (void) putchar('\n'); 2775 0 stevel } 2776 0 stevel #undef RTA_IGN 2777 0 stevel } 2778 0 stevel 2779 1676 jpk static void 2780 1676 jpk pmsg_common(const struct rt_msghdr *rtm, size_t msglen) 2781 0 stevel { 2782 0 stevel (void) printf("\nlocks: "); 2783 0 stevel bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames); 2784 0 stevel (void) printf(" inits: "); 2785 0 stevel bprintf(stdout, (int)rtm->rtm_inits, metricnames); 2786 1676 jpk pmsg_addrs((const char *)(rtm + 1), msglen - sizeof (*rtm), 2787 1676 jpk rtm->rtm_addrs); 2788 0 stevel } 2789 0 stevel 2790 1676 jpk static void 2791 1676 jpk pmsg_addrs(const char *cp, size_t msglen, uint_t addrs) 2792 0 stevel { 2793 1676 jpk const struct sockaddr *sa; 2794 1676 jpk const char *maxptr; 2795 0 stevel int i; 2796 0 stevel 2797 1676 jpk if (addrs != 0) { 2798 1676 jpk (void) printf("\nsockaddrs: "); 2799 1676 jpk bprintf(stdout, addrs, addrnames); 2800 1676 jpk (void) putchar('\n'); 2801 1676 jpk maxptr = cp + msglen; 2802 1676 jpk for (i = 1; i != 0 && cp + sizeof (*sa) <= maxptr; i <<= 1) { 2803 1676 jpk if (i & addrs) { 2804 1676 jpk /* LINTED */ 2805 1676 jpk sa = (const struct sockaddr *)cp; 2806 1676 jpk (void) printf(" %s", routename(sa)); 2807 1676 jpk ADVANCE(cp, sa); 2808 1676 jpk } 2809 0 stevel } 2810 1676 jpk if (i != 0) 2811 1676 jpk msglen = 0; 2812 1676 jpk else 2813 1676 jpk msglen = maxptr - cp; 2814 0 stevel } 2815 1676 jpk pmsg_secattr(cp, msglen, "secattr: "); 2816 0 stevel (void) putchar('\n'); 2817 0 stevel (void) fflush(stdout); 2818 0 stevel } 2819 0 stevel 2820 0 stevel void 2821 0 stevel bprintf(FILE *fp, int b, char *s) 2822 0 stevel { 2823 0 stevel int i; 2824 0 stevel boolean_t gotsome = B_FALSE; 2825 0 stevel 2826 0 stevel if (b == 0) 2827 0 stevel return; 2828 0 stevel while ((i = *s++) != 0) { 2829 0 stevel if (b & (1 << (i - 1))) { 2830 0 stevel if (!gotsome) 2831 0 stevel i = '<'; 2832 0 stevel else 2833 0 stevel i = ','; 2834 0 stevel (void) putc(i, fp); 2835 0 stevel gotsome = B_TRUE; 2836 0 stevel for (; (i = *s) > ' '; s++) 2837 0 stevel (void) putc(i, fp); 2838 0 stevel } else { 2839 0 stevel while (*s > ' ') 2840 0 stevel s++; 2841 0 stevel } 2842 0 stevel } 2843 0 stevel if (gotsome) 2844 0 stevel (void) putc('>', fp); 2845 0 stevel } 2846 0 stevel 2847 0 stevel int 2848 1291 jl138328 keyword(const char *cp) 2849 0 stevel { 2850 0 stevel struct keytab *kt = keywords; 2851 0 stevel 2852 0 stevel while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 2853 0 stevel kt++; 2854 0 stevel return (kt->kt_i); 2855 0 stevel } 2856 0 stevel 2857 0 stevel void 2858 1291 jl138328 sodump(su_t *su, char *which) 2859 0 stevel { 2860 0 stevel static char obuf[INET6_ADDRSTRLEN]; 2861 0 stevel 2862 0 stevel switch (su->sa.sa_family) { 2863 0 stevel case AF_LINK: 2864 0 stevel (void) printf("%s: link %s; ", 2865 0 stevel which, link_ntoa(&su->sdl)); 2866 0 stevel break; 2867 0 stevel case AF_INET: 2868 0 stevel (void) printf("%s: inet %s; ", 2869 0 stevel which, inet_ntoa(su->sin.sin_addr)); 2870 0 stevel break; 2871 0 stevel case AF_INET6: 2872 0 stevel if (inet_ntop(AF_INET6, (void *)&su->sin6.sin6_addr, obuf, 2873 0 stevel INET6_ADDRSTRLEN) != NULL) { 2874 0 stevel (void) printf("%s: inet6 %s; ", which, obuf); 2875 0 stevel break; 2876 0 stevel } 2877 0 stevel /* FALLTHROUGH */ 2878 0 stevel default: 2879 0 stevel quit(gettext("Internal Error"), EINVAL); 2880 0 stevel /* NOTREACHED */ 2881 0 stevel } 2882 0 stevel (void) fflush(stdout); 2883 0 stevel } 2884 0 stevel 2885 0 stevel /* States */ 2886 0 stevel #define VIRGIN 0 2887 0 stevel #define GOTONE 1 2888 0 stevel #define GOTTWO 2 2889 0 stevel #define RESET 3 2890 0 stevel /* Inputs */ 2891 0 stevel #define DIGIT (4*0) 2892 0 stevel #define END (4*1) 2893 0 stevel #define DELIM (4*2) 2894 0 stevel #define LETTER (4*3) 2895 0 stevel 2896 0 stevel void 2897 0 stevel sockaddr(char *addr, struct sockaddr *sa) 2898 0 stevel { 2899 0 stevel char *cp = (char *)sa; 2900 0 stevel int size = salen(sa); 2901 0 stevel char *cplim = cp + size; 2902 0 stevel int byte = 0, state = VIRGIN, new; 2903 0 stevel 2904 0 stevel (void) memset(cp, 0, size); 2905 0 stevel cp++; 2906 0 stevel do { 2907 0 stevel if ((*addr >= '0') && (*addr <= '9')) { 2908 0 stevel new = *addr - '0'; 2909 0 stevel } else if ((*addr >= 'a') && (*addr <= 'f')) { 2910 0 stevel new = *addr - 'a' + 10; 2911 0 stevel } else if ((*addr >= 'A') && (*addr <= 'F')) { 2912 0 stevel new = *addr - 'A' + 10; 2913 0 stevel } else if (*addr == 0) { 2914 0 stevel state |= END; 2915 0 stevel } else { 2916 0 stevel state |= DELIM; 2917 0 stevel } 2918 0 stevel addr++; 2919 0 stevel switch (state /* | INPUT */) { 2920 0 stevel case GOTTWO | DIGIT: 2921 0 stevel *cp++ = byte; 2922 0 stevel /* FALLTHROUGH */ 2923 0 stevel case VIRGIN | DIGIT: 2924 0 stevel state = GOTONE; byte = new; continue; 2925 0 stevel case GOTONE | DIGIT: 2926 0 stevel state = GOTTWO; byte = new + (byte << 4); continue; 2927 0 stevel default: /* | DELIM */ 2928 0 stevel state = VIRGIN; *cp++ = byte; byte = 0; continue; 2929 0 stevel case GOTONE | END: 2930 0 stevel case GOTTWO | END: 2931 0 stevel *cp++ = byte; 2932 0 stevel /* FALLTHROUGH */ 2933 0 stevel case VIRGIN | END: 2934 0 stevel break; 2935 0 stevel } 2936 0 stevel break; 2937 0 stevel } while (cp < cplim); 2938 0 stevel } 2939 0 stevel 2940 0 stevel int 2941 1676 jpk salen(const struct sockaddr *sa) 2942 0 stevel { 2943 0 stevel switch (sa->sa_family) { 2944 0 stevel case AF_INET: 2945 0 stevel return (sizeof (struct sockaddr_in)); 2946 0 stevel case AF_LINK: 2947 0 stevel return (sizeof (struct sockaddr_dl)); 2948 0 stevel case AF_INET6: 2949 0 stevel return (sizeof (struct sockaddr_in6)); 2950 0 stevel default: 2951 0 stevel return (sizeof (struct sockaddr)); 2952 0 stevel } 2953 0 stevel } 2954 0 stevel 2955 0 stevel void 2956 0 stevel link_addr(const char *addr, struct sockaddr_dl *sdl) 2957 0 stevel { 2958 0 stevel char *cp = sdl->sdl_data; 2959 0 stevel char *cplim = sizeof (struct sockaddr_dl) + (char *)sdl; 2960 0 stevel int byte = 0, state = VIRGIN, new; 2961 0 stevel 2962 0 stevel (void) memset(sdl, 0, sizeof (struct sockaddr_dl)); 2963 0 stevel sdl->sdl_family = AF_LINK; 2964 0 stevel do { 2965 0 stevel state &= ~LETTER; 2966 0 stevel if ((*addr >= '0') && (*addr <= '9')) { 2967 0 stevel new = *addr - '0'; 2968 0 stevel } else if ((*addr >= 'a') && (*addr <= 'f')) { 2969 0 stevel new = *addr - 'a' + 10; 2970 0 stevel } else if ((*addr >= 'A') && (*addr <= 'F')) { 2971 0 stevel new = *addr - 'A' + 10; 2972 0 stevel } else if (*addr == 0) { 2973 0 stevel state |= END; 2974 0 stevel } else if (state == VIRGIN && 2975 0 stevel (((*addr >= 'A') && (*addr <= 'Z')) || 2976 0 stevel ((*addr >= 'a') && (*addr <= 'z')))) { 2977 0 stevel state |= LETTER; 2978 0 stevel } else { 2979 0 stevel state |= DELIM; 2980 0 stevel } 2981 0 stevel addr++; 2982 0 stevel switch (state /* | INPUT */) { 2983 0 stevel case VIRGIN | DIGIT: 2984 0 stevel case VIRGIN | LETTER: 2985 0 stevel *cp++ = addr[-1]; 2986 0 stevel continue; 2987 0 stevel case VIRGIN | DELIM: 2988 0 stevel state = RESET; 2989 0 stevel sdl->sdl_nlen = cp - sdl->sdl_data; 2990 0 stevel continue; 2991 0 stevel case GOTTWO | DIGIT: 2992 0 stevel *cp++ = byte; 2993 0 stevel /* FALLTHROUGH */ 2994 0 stevel case RESET | DIGIT: 2995 0 stevel state = GOTONE; 2996 0 stevel byte = new; 2997 0 stevel continue; 2998 0 stevel case GOTONE | DIGIT: 2999 0 stevel state = GOTTWO; 3000 0 stevel byte = new + (byte << 4); 3001 0 stevel continue; 3002 0 stevel default: /* | DELIM */ 3003 0 stevel state = RESET; 3004 0 stevel *cp++ = byte; 3005 0 stevel byte = 0; 3006 0 stevel continue; 3007 0 stevel case GOTONE | END: 3008 0 stevel case GOTTWO | END: 3009 0 stevel *cp++ = byte; 3010 0 stevel /* FALLTHROUGH */ 3011 0 stevel case RESET | END: 3012 0 stevel break; 3013 0 stevel } 3014 0 stevel break; 3015 0 stevel } while (cp < cplim); 3016 0 stevel sdl->sdl_alen = cp - LLADDR(sdl); 3017 0 stevel } 3018 0 stevel 3019 0 stevel static char hexlist[] = "0123456789abcdef"; 3020 0 stevel 3021 0 stevel char * 3022 0 stevel link_ntoa(const struct sockaddr_dl *sdl) 3023 0 stevel { 3024 0 stevel static char obuf[64]; 3025 0 stevel char *out = obuf; 3026 0 stevel int i; 3027 0 stevel uchar_t *in = (uchar_t *)LLADDR(sdl); 3028 0 stevel uchar_t *inlim = in + sdl->sdl_alen; 3029 0 stevel boolean_t firsttime = B_TRUE; 3030 0 stevel 3031 0 stevel if (sdl->sdl_nlen) { 3032 0 stevel (void) memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen); 3033 0 stevel out += sdl->sdl_nlen; 3034 0 stevel if (sdl->sdl_alen) 3035 0 stevel *out++ = ':'; 3036 0 stevel } 3037 0 stevel while (in < inlim) { 3038 0 stevel if (firsttime) 3039 0 stevel firsttime = B_FALSE; 3040 0 stevel else 3041 0 stevel *out++ = '.'; 3042 0 stevel i = *in++; 3043 0 stevel if (i > 0xf) { 3044 0 stevel out[1] = hexlist[i & 0xf]; 3045 0 stevel i >>= 4; 3046 0 stevel out[0] = hexlist[i]; 3047 0 stevel out += 2; 3048 0 stevel } else { 3049 0 stevel *out++ = hexlist[i]; 3050 0 stevel } 3051 0 stevel } 3052 0 stevel *out = 0; 3053 0 stevel return (obuf); 3054 0 stevel } 3055 0 stevel 3056 0 stevel static mib_item_t * 3057 0 stevel mibget(int sd) 3058 0 stevel { 3059 0 stevel intmax_t buf[512 / sizeof (intmax_t)]; 3060 0 stevel int flags; 3061 0 stevel int i, j, getcode; 3062 0 stevel struct strbuf ctlbuf, databuf; 3063 0 stevel struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; 3064 0 stevel struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; 3065 0 stevel struct T_error_ack *tea = (struct T_error_ack *)buf; 3066 0 stevel struct opthdr *req; 3067 0 stevel mib_item_t *first_item = NULL; 3068 0 stevel mib_item_t *last_item = NULL; 3069 0 stevel mib_item_t *temp; 3070 0 stevel 3071