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