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